From ea0f9e6ce95b45def2b694efcd8ffe909bc43d20 Mon Sep 17 00:00:00 2001 From: Anthony Dresser Date: Sun, 15 Sep 2019 22:38:26 -0700 Subject: [PATCH] Merge from vscode 64980ea1f3f532c82bb6c28d27bba9ef2c5b4463 (#7206) * Merge from vscode 64980ea1f3f532c82bb6c28d27bba9ef2c5b4463 * fix config changes * fix strictnull checks --- .prettierrc.json | 6 + .yarnrc | 2 +- build/.cachesalt | 2 +- .../azure-pipelines/common/publish-webview.sh | 9 + .../azure-pipelines/common/publish-webview.ts | 87 + .../darwin/continuous-build-darwin.yml | 7 +- .../darwin/product-build-darwin.yml | 28 +- build/azure-pipelines/exploration-build.yml | 17 +- .../linux/continuous-build-linux.yml | 7 +- .../linux/product-build-linux-multiarch.yml | 2 +- .../linux/product-build-linux.yml | 9 +- .../linux/snap-build-linux.yml | 4 +- build/azure-pipelines/product-build.yml | 4 +- build/azure-pipelines/product-compile.yml | 14 +- .../publish-types/publish-types.yml | 18 +- build/azure-pipelines/sync-mooncake.yml | 2 +- .../azure-pipelines/web/product-build-web.yml | 2 +- .../win32/continuous-build-win32.yml | 10 +- .../win32/product-build-win32.yml | 11 +- build/gulpfile.extensions.js | 37 +- build/gulpfile.hygiene.js | 95 +- build/gulpfile.vscode.js | 8 +- build/gulpfile.vscode.linux.js | 17 +- build/gulpfile.vscode.web.js | 151 +- build/lib/compilation.js | 41 +- build/lib/compilation.ts | 54 +- build/lib/extensions.js | 2 +- build/lib/i18n.js | 12 +- build/lib/i18n.resources.json | 4 + build/lib/i18n.ts | 10 +- build/lib/optimize.js | 46 +- build/lib/optimize.ts | 53 +- .../lib/tslint/noUnexternalizedStringsRule.js | 3 + .../lib/tslint/noUnexternalizedStringsRule.ts | 3 + build/lib/typings/gulp-tsb.d.ts | 12 +- build/lib/util.js | 2 +- build/lib/util.ts | 2 +- build/lib/watch/index.js | 14 +- build/monaco/api.js | 5 +- build/monaco/api.ts | 5 +- build/monaco/monaco.d.ts.recipe | 1 + build/monaco/package.json | 2 +- build/npm/postinstall.js | 1 + build/package.json | 6 +- build/yarn.lock | 130 +- cglicenses.json | 2 + cgmanifest.json | 4 +- .../admin-tool-ext-win/{src => }/config.json | 0 extensions/admin-tool-ext-win/src/main.ts | 8 +- extensions/agent/package.json | 2 +- extensions/agent/src/dialogs/jobStepDialog.ts | 22 +- extensions/agent/yarn.lock | 8 +- extensions/cms/package.json | 2 +- extensions/cms/yarn.lock | 8 +- .../src/wizard/pages/deployConfigPage.ts | 6 +- .../dacpac/src/wizard/pages/deployPlanPage.ts | 4 +- .../src/wizard/pages/exportConfigPage.ts | 6 +- .../src/wizard/pages/extractConfigPage.ts | 6 +- .../src/wizard/pages/importConfigPage.ts | 6 +- .../src/wizard/pages/selectOperationpage.ts | 4 +- extensions/git/package.nls.json | 2 +- extensions/git/src/commands.ts | 2 +- extensions/git/src/decorationProvider.ts | 25 +- extensions/git/src/git.ts | 4 +- extensions/git/src/repository.ts | 11 +- extensions/git/src/statusbar.ts | 1 + extensions/image-preview/.vscodeignore | 10 + extensions/image-preview/README.md | 3 + .../image-preview/extension.webpack.config.js | 20 + extensions/image-preview/media/main.css | 78 + extensions/image-preview/media/main.js | 258 + extensions/image-preview/package.json | 43 + extensions/image-preview/package.nls.json | 5 + extensions/image-preview/src/dispose.ts | 42 + extensions/image-preview/src/extension.ts | 28 + extensions/image-preview/src/preview.ts | 113 + .../image-preview/src/sizeStatusBarEntry.ts | 33 + extensions/image-preview/src/typings/ref.d.ts | 8 + .../image-preview/src/zoomStatusBarEntry.ts | 68 + extensions/image-preview/tsconfig.json | 10 + extensions/image-preview/yarn.lock | 46 + .../import/{src/services => }/config.json | 0 .../import/src/services/serviceClient.ts | 10 +- .../import/src/services/serviceUtils.ts | 21 - .../src/wizard/pages/modifyColumnsPage.ts | 6 +- extensions/integration-tests/package.json | 2 +- extensions/integration-tests/yarn.lock | 8 +- .../server/package.json | 2 +- .../server/src/jsonServerMain.ts | 2 +- .../json-language-features/server/yarn.lock | 15 +- extensions/json/package.json | 3 +- .../syntaxes/markdown.tmLanguage.json | 406 +- .../markdown-language-features/media/index.js | 2 +- .../markdown-language-features/media/pre.js | 2 +- .../markdown-language-features/package.json | 20 +- .../package.nls.json | 11 +- .../preview-src/tsconfig.json | 12 +- .../src/commands/openDocumentLink.ts | 52 +- .../src/docIndex.ts | 50 + .../src/features/documentLinkProvider.ts | 4 +- .../src/features/preview.ts | 19 +- .../src/features/workspaceSymbolProvider.ts | 37 +- .../src/security.ts | 8 +- .../src/tableOfContentsProvider.ts | 14 +- extensions/mssql/{src => }/config.json | 0 .../src/credentialstore/credentialstore.ts | 4 +- .../src/resourceProvider/resourceProvider.ts | 6 +- extensions/mssql/src/sqlToolsServer.ts | 11 +- extensions/package.json | 2 +- extensions/powershell/cgmanifest.json | 2 +- extensions/schema-compare/package.json | 2 +- .../src/dialogs/schemaCompareDialog.ts | 6 +- extensions/schema-compare/yarn.lock | 8 +- .../theme-abyss/themes/abyss-color-theme.json | 6 +- .../themes/kimbie-dark-color-theme.json | 3 +- .../themes/dimmed-monokai-color-theme.json | 3 +- .../themes/monokai-color-theme.json | 1 + .../themes/quietlight-color-theme.json | 5 +- .../theme-red/themes/Red-color-theme.json | 3 +- .../themes/solarized-dark-color-theme.json | 1 + .../themes/solarized-light-color-theme.json | 3 +- .../themes/tomorrow-night-blue-theme.json | 3 +- .../vscode-test-resolver/src/extension.ts | 13 +- extensions/yarn.lock | 8 +- package.json | 27 +- remote/package.json | 12 +- remote/web/package.json | 16 +- remote/web/yarn.lock | 26 +- remote/yarn.lock | 102 +- resources/linux/bin/code.sh | 2 +- resources/linux/code-url-handler.desktop | 2 +- resources/linux/code.desktop | 4 +- resources/linux/snap/snapcraft.yaml | 2 - resources/win32/bin/code.sh | 2 +- scripts/code.sh | 6 +- ...est-release.bat => test-documentation.bat} | 2 + ...{test-release.sh => test-documentation.sh} | 2 + scripts/test-integration.bat | 35 +- scripts/test-integration.sh | 34 +- scripts/test.bat | 4 +- scripts/test.sh | 6 +- src/bootstrap-window.js | 2 +- src/bootstrap.js | 6 +- src/buildfile.js | 12 +- .../table/plugins/autoSizeColumns.plugin.ts | 2 +- .../plugins/checkboxSelectColumn.plugin.ts | 2 +- .../ui/table/plugins/headerFilter.plugin.ts | 35 +- .../accounts/browser/accountDialog.ts | 2 +- .../accounts/browser/accountPicker.ts | 2 +- .../accounts/browser/accountPickerImpl.ts | 2 +- .../accounts/browser/accountPickerService.ts | 2 +- .../platform/accounts/common/interfaces.ts | 2 +- .../common/testAccountManagementService.ts | 2 +- .../common/angularEventingService.ts | 2 +- .../node/angularEventingService.ts | 2 +- .../platform/backup/common/backupService.ts | 2 +- .../backup/common/backupServiceImp.ts | 2 +- .../common/capabilitiesService.ts | 2 +- .../common/capabilitiesServiceImpl.ts | 2 +- .../test/common/testCapabilitiesService.ts | 2 +- .../electron-browser/clipboardService.ts | 2 +- .../browser/connectionManagementService.ts | 2 +- .../connection/common/connectionManagement.ts | 2 +- .../test/common/testConfigurationService.ts | 2 +- .../common/testConnectionManagementService.ts | 2 +- .../credentials/common/credentialsService.ts | 4 +- .../test/common/testCredentialsService.ts | 2 +- .../dashboard/browser/dashboardService.ts | 2 +- .../dashboard/browser/dashboardServiceImpl.ts | 2 +- .../dashboard/browser/dashboardViewService.ts | 2 +- .../browser/dashboardViewServiceImpl.ts | 2 +- .../common/errorMessageService.ts | 2 +- .../test/common/testErrorMessageService.ts | 4 +- .../fileBrowser/common/fileBrowserService.ts | 2 +- .../platform/fileBrowser/common/interfaces.ts | 4 +- .../jobManagement/common/interfaces.ts | 2 +- .../common/jobManagementService.ts | 10 +- .../metadata/common/metadataService.ts | 4 +- .../browser/modelViewService.ts | 2 +- .../browser/modelViewServiceImpl.ts | 2 +- .../platform/oAuth/common/sqlOAuthService.ts | 2 +- .../electron-browser/sqlOAuthServiceImpl.ts | 2 +- .../platform/query/common/queryManagement.ts | 4 +- src/sql/platform/query/common/queryModel.ts | 2 +- .../query/common/queryModelService.ts | 2 +- .../restore/browser/restoreServiceImpl.ts | 4 +- .../platform/restore/common/restoreService.ts | 4 +- .../scripting/common/scriptingService.ts | 4 +- .../common/serializationService.ts | 4 +- .../common/serverGroupController.ts | 2 +- src/sql/platform/tasks/common/tasksService.ts | 6 +- .../telemetry/common/adsTelemetryService.ts | 2 +- .../platform/telemetry/common/telemetry.ts | 2 +- .../workbench/api/common/extHostNotebook.ts | 6 +- .../modelComponents/queryTextEditor.ts | 3 +- .../browser/parts/views/customView.ts | 53 +- .../parts/charts/browser/interfaces.ts | 2 +- .../test/electron-browser/commandLine.test.ts | 18 +- .../test/electron-browser/cell.test.ts | 14 +- .../browser/objectExplorerViewTreeShim.ts | 4 +- .../browser/connectionTreeActions.test.ts | 2 +- .../parts/profiler/browser/profilerEditor.ts | 6 +- .../parts/profiler/browser/profilerInput.ts | 8 +- .../profiler/browser/profilerTableEditor.ts | 4 +- .../parts/query/browser/queryResultsEditor.ts | 6 +- .../queryHistory/browser/queryHistoryView.ts | 8 +- .../parts/tasks/browser/tasksView.ts | 8 +- .../browser/accountManagementService.ts | 2 +- .../services/admin/common/adminService.ts | 4 +- .../backup/browser/backupUiService.ts | 2 +- .../services/backup/common/backupUiService.ts | 2 +- .../browser/connectionDialogService.ts | 10 +- .../common/connectionDialogService.ts | 2 +- .../common/testConnectionDialogService.ts | 2 +- .../browser/newDashboardTabDialog.ts | 2 +- .../browser/newDashboardTabDialogImpl.ts | 2 +- .../browser/newDashboardTabDialogService.ts | 2 +- .../browser/errorMessageService.ts | 4 +- .../browser/fileBrowserDialogController.ts | 2 +- .../browser/fileBrowserTreeView.ts | 8 +- .../common/fileBrowserDialogController.ts | 2 +- .../insights/browser/insightsDialogService.ts | 2 +- .../browser/insightsDialogServiceImpl.ts | 2 +- .../electron-browser/insightsUtils.test.ts | 2 +- .../notebook/browser/notebookService.ts | 2 +- .../notebook/browser/notebookServiceImpl.ts | 2 +- .../browser/objectExplorerService.ts | 14 +- .../services/profiler/browser/interfaces.ts | 4 +- .../profiler/browser/profilerService.ts | 2 +- .../browser/editorDescriptorService.ts | 6 +- .../queryEditor/browser/queryEditorService.ts | 2 +- .../queryEditor/common/queryEditorService.ts | 2 +- .../browser/resourceProviderService.ts | 2 +- .../common/resourceProviderService.ts | 2 +- .../common/testResourceProviderService.ts | 2 +- .../browser/serverGroupController.ts | 2 +- .../update/electron-browser/releaseNotes.ts | 2 +- src/tsconfig.base.json | 1 - src/tsconfig.json | 10 +- src/typings/electron.d.ts | 4 +- src/typings/globals/core-js/index.d.ts | 5 - src/typings/jQuery.d.ts | 5 +- src/typings/xterm.d.ts | 35 - src/vs/base/browser/dnd.ts | 2 +- src/vs/base/browser/dom.ts | 2 +- src/vs/base/browser/markdownRenderer.ts | 5 +- src/vs/base/browser/ui/dialog/dialog.ts | 33 +- src/vs/base/browser/ui/grid/grid.ts | 2 +- src/vs/base/browser/ui/grid/gridview.ts | 4 +- src/vs/base/browser/ui/iconLabel/iconLabel.ts | 12 +- src/vs/base/browser/ui/inputbox/inputBox.css | 4 + src/vs/base/browser/ui/inputbox/inputBox.ts | 75 +- src/vs/base/browser/ui/list/list.ts | 7 + src/vs/base/browser/ui/list/listPaging.ts | 3 +- src/vs/base/browser/ui/list/listView.ts | 14 +- src/vs/base/browser/ui/list/listWidget.ts | 21 +- src/vs/base/browser/ui/list/rangeMap.ts | 4 - src/vs/base/browser/ui/list/rowCache.ts | 14 +- src/vs/base/browser/ui/menu/menubar.ts | 2 +- .../octicons/octicons-animations.css | 2 +- .../octiconLabel/octicons/octicons-main.css | 4 - .../ui/octiconLabel/octicons/octicons2.css | 8 +- .../ui/octiconLabel/octicons/octicons2.svg | 567 --- .../ui/octiconLabel/octicons/octicons2.ttf | Bin 35588 -> 35196 bytes .../browser/ui/progressbar/progressbar.ts | 6 +- src/vs/base/browser/ui/sash/sash.ts | 65 +- .../browser/ui/selectBox/selectBoxCustom.ts | 2 +- .../base/browser/ui/splitview/splitview.css | 14 +- src/vs/base/browser/ui/splitview/splitview.ts | 29 +- src/vs/base/browser/ui/tree/abstractTree.ts | 91 +- src/vs/base/browser/ui/tree/asyncDataTree.ts | 262 +- .../browser/ui/tree/compressedObjectTree.ts | 56 - .../ui/tree/compressedObjectTreeModel.ts | 270 +- src/vs/base/browser/ui/tree/dataTree.ts | 15 +- src/vs/base/browser/ui/tree/indexTree.ts | 11 +- src/vs/base/browser/ui/tree/indexTreeModel.ts | 153 +- src/vs/base/browser/ui/tree/objectTree.ts | 127 +- .../base/browser/ui/tree/objectTreeModel.ts | 49 +- src/vs/base/browser/ui/tree/tree.ts | 31 +- src/vs/base/common/amd.ts | 8 + src/vs/base/common/collections.ts | 11 +- src/vs/base/common/console.ts | 6 +- src/vs/base/common/filters.ts | 167 +- src/vs/base/common/json.ts | 26 +- src/vs/base/common/jsonEdit.ts | 12 +- src/vs/base/common/jsonSchema.ts | 1 + src/vs/base/common/labels.ts | 2 +- src/vs/base/common/map.ts | 4 +- src/vs/base/common/network.ts | 17 +- src/vs/base/common/platform.ts | 25 +- src/vs/base/common/process.ts | 4 +- src/vs/base/common/search.ts | 10 +- src/vs/base/common/strings.ts | 11 +- src/vs/base/node/config.ts | 18 +- src/vs/base/node/languagePacks.js | 4 +- .../quickopen/browser/quickOpenWidget.ts | 18 +- src/vs/base/parts/storage/node/storage.ts | 4 +- src/vs/base/parts/tree/browser/treeImpl.ts | 18 +- src/vs/base/parts/tree/browser/treeModel.ts | 14 +- src/vs/base/parts/tree/browser/treeView.ts | 6 +- .../test/browser/ui/list/rangeMap.test.ts | 6 +- .../browser/ui/tree/asyncDataTree.test.ts | 404 +- .../ui/tree/compressedObjectTreeModel.test.ts | 12 +- .../test/browser/ui/tree/dataTree.test.ts | 4 +- .../browser/ui/tree/indexTreeModel.test.ts | 107 +- .../test/browser/ui/tree/objectTree.test.ts | 173 +- .../browser/ui/tree/objectTreeModel.test.ts | 20 +- src/vs/base/test/common/filters.test.ts | 4 + src/vs/base/test/node/glob.test.ts | 54 +- src/vs/base/test/node/keytar.test.ts | 2 + src/vs/base/worker/workerMain.ts | 4 +- src/vs/code/browser/workbench/callback.html | 79 + .../code/browser/workbench/workbench-dev.html | 62 + src/vs/code/browser/workbench/workbench.html | 35 +- src/vs/code/browser/workbench/workbench.js | 32 - src/vs/code/browser/workbench/workbench.ts | 208 + .../issue/issueReporterMain.ts | 5 +- .../sharedProcess/sharedProcessMain.ts | 14 +- .../electron-browser/workbench/workbench.js | 2 +- src/vs/code/electron-main/app.ts | 21 +- src/vs/code/electron-main/auth.ts | 2 +- src/vs/code/electron-main/main.ts | 2 +- src/vs/code/electron-main/window.ts | 6 +- src/vs/code/electron-main/windows.ts | 83 +- src/vs/code/node/cli.ts | 14 +- src/vs/code/node/cliProcessMain.ts | 17 +- src/vs/code/node/shellEnv.ts | 2 +- src/vs/code/node/windowsFinder.ts | 25 +- src/vs/code/test/node/argv.test.ts | 33 +- .../editor/browser/config/charWidthReader.ts | 5 +- src/vs/editor/browser/config/configuration.ts | 4 +- .../editor/browser/controller/coreCommands.ts | 38 +- .../editor/browser/controller/mouseHandler.ts | 12 +- .../editor/browser/controller/mouseTarget.ts | 14 +- .../browser/controller/textAreaHandler.ts | 86 +- .../browser/controller/textAreaInput.ts | 5 + .../browser/core/keybindingCancellation.ts | 4 +- src/vs/editor/browser/editorBrowser.ts | 28 +- .../services/abstractCodeEditorService.ts | 2 +- .../browser/services/bulkEditService.ts | 2 +- .../browser/services/codeEditorService.ts | 2 +- .../editor/browser/services/openerService.ts | 3 +- src/vs/editor/browser/view/viewController.ts | 17 +- src/vs/editor/browser/view/viewImpl.ts | 21 +- src/vs/editor/browser/view/viewLayer.ts | 6 +- src/vs/editor/browser/view/viewOverlays.ts | 42 +- .../contentWidgets/contentWidgets.ts | 25 +- .../currentLineHighlight.ts | 30 +- .../currentLineMarginHighlight.ts | 29 +- .../viewParts/decorations/decorations.ts | 15 +- .../editorScrollbar/editorScrollbar.ts | 57 +- .../viewParts/glyphMargin/glyphMargin.ts | 31 +- .../viewParts/indentGuides/indentGuides.ts | 41 +- .../viewParts/lineNumbers/lineNumbers.ts | 18 +- .../browser/viewParts/lines/viewLine.ts | 22 +- .../browser/viewParts/lines/viewLines.ts | 75 +- .../linesDecorations/linesDecorations.ts | 18 +- .../editor/browser/viewParts/margin/margin.ts | 27 +- .../browser/viewParts/minimap/minimap.ts | 70 +- .../overlayWidgets/overlayWidgets.ts | 33 +- .../overviewRuler/decorationsOverviewRuler.ts | 20 +- .../viewParts/overviewRuler/overviewRuler.ts | 17 +- .../editor/browser/viewParts/rulers/rulers.ts | 16 +- .../scrollDecoration/scrollDecoration.ts | 38 +- .../viewParts/selections/selections.ts | 23 +- .../viewParts/viewCursors/viewCursor.ts | 33 +- .../viewParts/viewCursors/viewCursors.ts | 31 +- .../browser/viewParts/viewZones/viewZones.ts | 25 +- .../editor/browser/widget/codeEditorWidget.ts | 67 +- .../editor/browser/widget/diffEditorWidget.ts | 79 +- src/vs/editor/browser/widget/diffReview.ts | 42 +- .../widget/embeddedCodeEditorWidget.ts | 16 +- .../editor/browser/widget/inlineDiffMargin.ts | 69 +- .../common/config/commonEditorConfig.ts | 1144 ++--- src/vs/editor/common/config/editorOptions.ts | 4210 +++++++++-------- src/vs/editor/common/config/fontInfo.ts | 102 +- src/vs/editor/common/controller/cursor.ts | 35 +- .../editor/common/controller/cursorCommon.ts | 62 +- .../common/controller/cursorTypeOperations.ts | 25 +- src/vs/editor/common/editorCommon.ts | 12 +- src/vs/editor/common/model/textModel.ts | 6 +- src/vs/editor/common/model/textModelSearch.ts | 3 +- src/vs/editor/common/modes.ts | 9 + .../common/services/editorWorkerService.ts | 2 +- .../services/editorWorkerServiceImpl.ts | 5 +- .../services/markerDecorationsServiceImpl.ts | 2 +- .../services/markersDecorationService.ts | 2 +- src/vs/editor/common/services/modeService.ts | 2 +- .../editor/common/services/modeServiceImpl.ts | 2 +- src/vs/editor/common/services/modelService.ts | 2 +- .../common/services/modelServiceImpl.ts | 2 +- .../editor/common/services/resolverService.ts | 2 +- .../common/services/resourceConfiguration.ts | 4 +- .../services/resourceConfigurationImpl.ts | 2 +- .../common/standalone/standaloneEnums.ts | 61 +- src/vs/editor/common/view/viewEvents.ts | 42 +- src/vs/editor/common/viewLayout/viewLayout.ts | 46 +- .../common/viewModel/viewModelDecorations.ts | 3 +- .../editor/common/viewModel/viewModelImpl.ts | 37 +- .../bracketMatching/bracketMatching.ts | 7 +- src/vs/editor/contrib/clipboard/clipboard.ts | 7 +- .../editor/contrib/codeAction/codeAction.ts | 4 +- .../contrib/codeAction/codeActionCommands.ts | 34 +- .../contrib/codeAction/codeActionModel.ts | 3 +- .../contrib/codeAction/lightBulbWidget.ts | 14 +- .../editor/contrib/codelens/codeLensCache.ts | 4 +- src/vs/editor/contrib/codelens/codelens.ts | 14 +- .../contrib/codelens/codelensController.ts | 7 +- .../editor/contrib/codelens/codelensWidget.ts | 5 +- .../contrib/colorPicker/colorDetector.ts | 3 +- .../editor/contrib/contextmenu/contextmenu.ts | 7 +- src/vs/editor/contrib/dnd/dnd.ts | 5 +- .../contrib/documentSymbols/outlineModel.ts | 3 + src/vs/editor/contrib/find/findController.ts | 23 +- src/vs/editor/contrib/find/findModel.ts | 15 +- src/vs/editor/contrib/find/findWidget.ts | 81 +- .../contrib/find/test/replacePattern.test.ts | 25 + src/vs/editor/contrib/folding/folding.ts | 20 +- src/vs/editor/contrib/format/formatActions.ts | 5 +- .../goToDefinition/clickLinkGesture.ts | 7 +- .../goToDefinition/goToDefinitionCommands.ts | 3 +- .../goToDefinitionResultsNavigation.ts | 4 +- .../contrib/gotoError/gotoErrorWidget.ts | 15 +- src/vs/editor/contrib/hover/hover.css | 4 + src/vs/editor/contrib/hover/hover.ts | 13 +- src/vs/editor/contrib/hover/hoverWidgets.ts | 36 +- .../editor/contrib/hover/modesContentHover.ts | 7 +- .../editor/contrib/indentation/indentation.ts | 3 +- .../linesOperations/linesOperations.ts | 5 +- src/vs/editor/contrib/links/links.ts | 11 +- .../contrib/markdown/markdownRenderer.ts | 3 +- .../editor/contrib/multicursor/multicursor.ts | 21 +- .../multicursor/test/multicursor.test.ts | 5 +- .../parameterHints/parameterHintsModel.ts | 7 +- .../parameterHints/parameterHintsWidget.ts | 10 +- .../contrib/referenceSearch/peekViewWidget.ts | 11 +- .../referenceSearch/referencesModel.ts | 4 +- .../referenceSearch/referencesWidget.ts | 10 +- .../editor/contrib/rename/renameInputField.ts | 7 +- .../editor/contrib/smartSelect/smartSelect.ts | 10 +- .../smartSelect/test/smartSelect.test.ts | 102 +- .../editor/contrib/snippet/snippetSession.ts | 3 +- .../contrib/snippet/snippetVariables.ts | 17 +- .../snippet/test/snippetVariables.test.ts | 26 +- .../editor/contrib/suggest/completionModel.ts | 9 +- .../editor/contrib/suggest/media/suggest.css | 8 + src/vs/editor/contrib/suggest/suggest.ts | 6 +- .../suggest/suggestCommitCharacters.ts | 3 +- .../contrib/suggest/suggestController.ts | 15 +- .../editor/contrib/suggest/suggestMemory.ts | 4 +- src/vs/editor/contrib/suggest/suggestModel.ts | 25 +- .../editor/contrib/suggest/suggestWidget.ts | 48 +- .../suggest/test/completionModel.test.ts | 114 +- .../contrib/suggest/test/suggestModel.test.ts | 2 +- .../editor/contrib/suggest/wordContextKey.ts | 5 +- src/vs/editor/contrib/suggest/wordDistance.ts | 71 +- .../wordHighlighter/wordHighlighter.ts | 23 +- .../contrib/wordOperations/wordOperations.ts | 18 +- .../editor/contrib/zoneWidget/zoneWidget.ts | 8 +- src/vs/editor/editor.api.ts | 9 +- src/vs/editor/editor.worker.ts | 4 +- .../accessibilityHelp/accessibilityHelp.ts | 15 +- .../iPadShowKeyboard/iPadShowKeyboard.ts | 3 +- .../quickOpen/quickOpenEditorWidget.ts | 8 +- .../standalone/browser/simpleServices.ts | 32 +- .../browser/standaloneCodeEditor.ts | 6 +- .../standalone/browser/standaloneEditor.ts | 10 +- .../browser/standaloneThemeServiceImpl.ts | 2 +- .../common/standaloneThemeService.ts | 2 +- .../test/browser/standaloneLanguages.test.ts | 4 +- .../trimTrailingWhitespaceCommand.test.ts | 28 +- .../test/browser/controller/cursor.test.ts | 39 +- .../controller/cursorMoveCommand.test.ts | 10 +- .../editor/test/browser/editorTestServices.ts | 2 +- .../browser/services/openerService.test.ts | 2 +- src/vs/editor/test/browser/testCodeEditor.ts | 7 +- .../common/config/commonEditorConfig.test.ts | 23 +- .../linesTextBuffer/linesTextBuffer.test.ts | 8 +- .../common/model/modelDecorations.test.ts | 4 +- .../test/common/model/textModelSearch.test.ts | 46 +- .../common/model/textModelWithTokens.test.ts | 8 +- .../modes/supports/tokenization.test.ts | 4 +- .../test/common/services/modelService.test.ts | 2 +- .../viewLayout/editorLayoutProvider.test.ts | 1052 ++-- .../common/viewLayout/lineDecorations.test.ts | 44 +- .../viewModel/splitLinesCollection.test.ts | 52 +- src/vs/monaco.d.ts | 759 ++- .../common/abstractAccessibilityService.ts | 2 +- .../accessibility/common/accessibility.ts | 2 +- .../common/accessibilityService.ts | 2 +- src/vs/platform/actions/common/actions.ts | 2 +- src/vs/platform/actions/common/menuService.ts | 2 +- src/vs/platform/backup/common/backup.ts | 2 +- .../backup/electron-main/backupMainService.ts | 12 +- .../electron-main/backupMainService.test.ts | 8 +- .../clipboard/browser/clipboardService.ts | 3 +- .../clipboard/common/clipboardService.ts | 2 +- .../electron-browser/clipboardService.ts | 2 +- src/vs/platform/commands/common/commands.ts | 2 +- .../configuration/common/configuration.ts | 2 +- .../common/configurationModels.ts | 2 +- .../common/configurationRegistry.ts | 11 +- .../node/configurationService.ts | 2 +- .../test/common/testConfigurationService.ts | 2 +- .../contextkey/browser/contextKeyService.ts | 2 +- .../platform/contextkey/common/contextkey.ts | 2 +- .../contextview/browser/contextMenuHandler.ts | 4 +- .../contextview/browser/contextMenuService.ts | 2 +- .../contextview/browser/contextView.ts | 4 +- .../contextview/browser/contextViewService.ts | 2 +- .../debug/common/extensionHostDebug.ts | 2 +- .../debug/common/extensionHostDebugIpc.ts | 2 +- .../diagnostics/node/diagnosticsIpc.ts | 3 +- .../diagnostics/node/diagnosticsService.ts | 14 +- .../platform/dialogs/browser/dialogService.ts | 15 +- src/vs/platform/dialogs/common/dialogs.ts | 28 +- src/vs/platform/dialogs/node/dialogIpc.ts | 8 +- src/vs/platform/download/common/download.ts | 2 +- .../platform/download/common/downloadIpc.ts | 2 +- .../download/common/downloadService.ts | 2 +- src/vs/platform/driver/common/driver.ts | 2 +- .../platform/driver/electron-main/driver.ts | 2 +- src/vs/platform/driver/node/driver.ts | 6 +- src/vs/platform/editor/common/editor.ts | 25 +- .../environment/common/environment.ts | 40 +- src/vs/platform/environment/node/argv.ts | 312 +- .../platform/environment/node/argvHelper.ts | 20 +- .../environment/node/environmentService.ts | 13 +- .../test/node/environmentService.test.ts | 12 +- .../common/extensionGalleryService.ts | 2 +- .../common/extensionManagement.ts | 4 +- .../common/extensionManagementIpc.ts | 2 +- .../node/extensionManagementService.ts | 2 +- .../test/node/extensionGalleryService.test.ts | 5 +- src/vs/platform/files/common/fileService.ts | 3 +- src/vs/platform/files/common/files.ts | 4 +- .../files/node/diskFileSystemProvider.ts | 2 +- .../node/watcher/nodejs/watcherService.ts | 4 +- .../node/watcher/nsfw/nsfwWatcherService.ts | 4 +- .../files/node/watcher/nsfw/watcherService.ts | 9 +- .../watcher/unix/chokidarWatcherService.ts | 10 +- .../files/node/watcher/unix/watcherService.ts | 11 +- src/vs/platform/history/common/history.ts | 2 +- .../electron-main/historyMainService.ts | 3 +- .../instantiation/common/instantiation.ts | 20 +- .../common/instantiationService.ts | 2 +- .../test/common/instantiationService.test.ts | 22 +- .../electron-browser/mainProcessService.ts | 6 +- .../electron-browser/sharedProcessService.ts | 6 +- .../issue/electron-browser/issueService.ts | 3 +- .../issue/electron-main/issueService.ts | 6 +- src/vs/platform/issue/node/issue.ts | 2 +- .../common/abstractKeybindingService.ts | 2 +- .../platform/keybinding/common/keybinding.ts | 2 +- .../common/abstractKeybindingService.test.ts | 3 +- .../test/common/mockKeybindingService.ts | 4 +- src/vs/platform/label/common/label.ts | 2 +- .../launch/electron-main/launchService.ts | 11 +- .../platform/layout/browser/layoutService.ts | 2 +- .../lifecycle/browser/lifecycleService.ts | 5 +- src/vs/platform/lifecycle/common/lifecycle.ts | 6 +- .../lifecycle/common/lifecycleService.ts | 3 +- .../electron-browser/lifecycleService.ts | 5 +- .../lifecycle/electron-main/lifecycleMain.ts | 12 +- src/vs/platform/list/browser/listService.ts | 56 +- .../localizations/common/localizations.ts | 2 +- .../electron-browser/localizationsService.ts | 3 +- .../localizations/node/localizations.ts | 2 +- src/vs/platform/log/common/bufferLog.ts | 9 +- src/vs/platform/log/common/fileLogService.ts | 15 +- src/vs/platform/log/common/log.ts | 12 +- src/vs/platform/log/common/logIpc.ts | 2 +- src/vs/platform/log/node/spdlogService.ts | 2 +- .../platform/markers/common/markerService.ts | 2 +- src/vs/platform/markers/common/markers.ts | 2 +- .../electron-browser/menubarService.ts | 3 +- .../platform/menubar/electron-main/menubar.ts | 47 +- .../menubar/electron-main/menubarService.ts | 2 +- src/vs/platform/menubar/node/menubar.ts | 2 +- .../notification/common/notification.ts | 4 +- .../test/common/testNotificationService.ts | 2 +- src/vs/platform/opener/common/opener.ts | 2 +- src/vs/platform/product/browser/product.ts | 21 + src/vs/platform/product/common/product.ts | 111 +- src/vs/platform/product/node/product.ts | 13 +- src/vs/platform/progress/common/progress.ts | 6 +- src/vs/platform/quickOpen/common/quickOpen.ts | 2 +- .../platform/quickinput/common/quickInput.ts | 2 +- .../browser/remoteAuthorityResolverService.ts | 10 +- .../remote/common/remoteAuthorityResolver.ts | 2 +- src/vs/platform/remote/common/tunnel.ts | 2 +- .../remote/{node => common}/tunnelService.ts | 7 +- .../remoteAuthorityResolverService.ts | 2 +- .../request/browser/requestService.ts | 2 +- src/vs/platform/request/common/request.ts | 2 +- src/vs/platform/request/common/requestIpc.ts | 2 +- .../platform/request/node/requestService.ts | 2 +- src/vs/platform/sign/browser/signService.ts | 3 +- src/vs/platform/sign/common/sign.ts | 2 +- src/vs/platform/sign/node/signService.ts | 2 +- src/vs/platform/state/common/state.ts | 2 +- src/vs/platform/state/node/stateService.ts | 2 +- src/vs/platform/statusbar/common/statusbar.ts | 6 +- .../storage/browser/storageService.ts | 7 +- src/vs/platform/storage/common/storage.ts | 16 +- src/vs/platform/storage/node/storageIpc.ts | 4 +- .../storage/node/storageMainService.ts | 8 +- .../platform/storage/node/storageService.ts | 3 +- .../storage/test/node/storageService.test.ts | 6 +- src/vs/platform/telemetry/common/telemetry.ts | 5 +- .../telemetry/common/telemetryService.ts | 5 +- .../telemetry/common/telemetryUtils.ts | 162 - .../telemetry/node/commonProperties.ts | 36 +- .../telemetry/node/telemetryNodeUtils.ts | 20 - .../node/workbenchCommonProperties.ts | 4 +- .../appInsightsAppender.test.ts | 2 +- .../electron-browser/commonProperties.test.ts | 8 +- .../electron-browser/telemetryService.test.ts | 46 +- src/vs/platform/theme/common/colorRegistry.ts | 1 + src/vs/platform/theme/common/themeService.ts | 2 +- .../theme/electron-main/themeMainService.ts | 4 +- .../theme/test/common/testThemeService.ts | 2 +- .../update.config.contribution.ts | 4 +- src/vs/platform/update/common/update.ts | 4 +- .../update/electron-browser/updateService.ts | 3 +- .../electron-main/abstractUpdateService.ts | 2 +- .../{node => electron-main}/updateIpc.ts | 0 .../electron-main/updateService.darwin.ts | 2 +- .../electron-main/updateService.linux.ts | 2 +- .../electron-main/updateService.snap.ts | 4 +- .../electron-main/updateService.win32.ts | 2 +- src/vs/platform/url/common/url.ts | 4 +- .../platform/url/{node => common}/urlIpc.ts | 40 +- src/vs/platform/url/common/urlService.ts | 3 +- src/vs/platform/url/node/urlService.ts | 6 +- src/vs/platform/windows/common/windows.ts | 4 +- .../electron-browser/windowsService.ts | 3 +- .../platform/windows/electron-main/windows.ts | 6 +- .../windows/electron-main/windowsService.ts | 17 +- src/vs/platform/workspace/common/workspace.ts | 2 +- .../platform/workspaces/common/workspaces.ts | 4 +- .../electron-browser/workspacesService.ts | 3 +- .../electron-main/workspacesMainService.ts | 2 +- .../workspacesMainService.test.ts | 4 +- src/vs/vscode.d.ts | 247 +- src/vs/vscode.proposed.d.ts | 366 +- .../api/browser/mainThreadCodeInsets.ts | 6 +- .../api/browser/mainThreadCommands.ts | 8 +- .../api/browser/mainThreadDebugService.ts | 23 +- .../api/browser/mainThreadDecorations.ts | 5 +- .../workbench/api/browser/mainThreadEditor.ts | 9 +- .../api/browser/mainThreadEditors.ts | 7 +- .../workbench/api/browser/mainThreadKeytar.ts | 4 + .../api/browser/mainThreadLanguageFeatures.ts | 41 +- .../api/browser/mainThreadMessageService.ts | 6 +- src/vs/workbench/api/browser/mainThreadSCM.ts | 7 +- .../api/browser/mainThreadSaveParticipant.ts | 30 +- .../workbench/api/browser/mainThreadTask.ts | 3 + .../api/browser/mainThreadTerminalService.ts | 34 +- .../api/browser/mainThreadTreeViews.ts | 11 +- .../workbench/api/browser/mainThreadUrls.ts | 8 +- .../api/browser/mainThreadWebview.ts | 101 +- .../api/common/configurationExtensionPoint.ts | 3 +- .../workbench/api/common/extHost.api.impl.ts | 14 +- .../workbench/api/common/extHost.protocol.ts | 33 +- .../api/common/extHostApiCommands.ts | 48 +- .../workbench/api/common/extHostCommands.ts | 23 +- .../api/common/extHostConfiguration.ts | 2 +- .../api/common/extHostDebugService.ts | 2 +- .../api/common/extHostDecorations.ts | 14 +- .../api/common/extHostDocumentsAndEditors.ts | 2 +- .../api/common/extHostExtensionActivator.ts | 21 +- .../api/common/extHostExtensionService.ts | 23 +- .../api/common/extHostLanguageFeatures.ts | 179 +- src/vs/workbench/api/common/extHostMemento.ts | 4 +- src/vs/workbench/api/common/extHostOutput.ts | 12 +- .../api/common/extHostRequireInterceptor.ts | 4 + .../workbench/api/common/extHostRpcService.ts | 4 +- src/vs/workbench/api/common/extHostSCM.ts | 6 +- src/vs/workbench/api/common/extHostStorage.ts | 2 +- .../api/common/extHostStoragePaths.ts | 2 +- src/vs/workbench/api/common/extHostTask.ts | 2 +- .../api/common/extHostTerminalService.ts | 569 ++- .../workbench/api/common/extHostTreeViews.ts | 24 + .../api/common/extHostTypeConverters.ts | 61 +- src/vs/workbench/api/common/extHostTypes.ts | 56 +- .../common/extHostUriTransformerService.ts | 4 +- src/vs/workbench/api/common/extHostWebview.ts | 74 +- .../workbench/api/common/extHostWorkspace.ts | 2 +- src/vs/workbench/api/common/shared/webview.ts | 5 +- .../workbench/api/node/extHostDebugService.ts | 18 +- .../api/node/extHostOutputService.ts | 16 +- src/vs/workbench/api/node/extHostSearch.ts | 4 +- src/vs/workbench/api/node/extHostTask.ts | 6 +- .../api/node/extHostTerminalService.ts | 549 +-- .../api/worker/extHostExtensionService.ts | 112 +- .../workbench/api/worker/extHostLogService.ts | 2 +- .../browser/actions/layoutActions.ts | 3 +- .../workbench/browser/actions/listCommands.ts | 9 +- src/vs/workbench/browser/composite.ts | 4 +- src/vs/workbench/browser/contextkeys.ts | 16 +- src/vs/workbench/browser/editor.ts | 2 +- src/vs/workbench/browser/labels.ts | 7 +- src/vs/workbench/browser/layout.ts | 70 +- src/vs/workbench/browser/media/part.css | 1 + src/vs/workbench/browser/part.ts | 4 +- .../parts/activitybar/activitybarPart.ts | 12 +- .../workbench/browser/parts/compositePart.ts | 3 +- .../browser/parts/editor/baseEditor.ts | 22 +- .../browser/parts/editor/binaryEditor.ts | 6 +- .../browser/parts/editor/breadcrumbs.ts | 6 +- .../browser/parts/editor/breadcrumbsPicker.ts | 3 +- .../parts/editor/editor.contribution.ts | 73 +- .../browser/parts/editor/editorCommands.ts | 5 +- .../browser/parts/editor/editorControl.ts | 9 +- .../browser/parts/editor/editorDropTarget.ts | 10 +- .../browser/parts/editor/editorGroupView.ts | 12 +- .../browser/parts/editor/editorPart.ts | 13 +- .../browser/parts/editor/editorStatus.ts | 17 +- .../editor/media/close-dirty-inverse-alt.svg | 1 - .../editor/media/close-dirty-inverse.svg | 1 - .../parts/editor/media/notabstitlecontrol.css | 1 + .../parts/editor/media/resourceviewer.css | 46 - .../parts/editor/media/tabstitlecontrol.css | 2 +- .../browser/parts/editor/resourceViewer.ts | 444 +- .../browser/parts/editor/sideBySideEditor.ts | 16 +- .../browser/parts/editor/textDiffEditor.ts | 43 +- .../browser/parts/editor/textEditor.ts | 6 +- .../parts/editor/textResourceEditor.ts | 8 +- .../browser/parts/editor/titleControl.ts | 4 +- .../parts/notifications/notificationsList.ts | 3 +- .../notifications/notificationsToasts.ts | 13 +- .../browser/parts/panel/media/panelpart.css | 1 - .../browser/parts/panel/panelPart.ts | 4 +- .../browser/parts/quickinput/quickInput.ts | 9 +- .../parts/quickinput/quickInputList.ts | 2 +- .../parts/quickopen/quickOpenController.ts | 12 +- .../browser/parts/sidebar/sidebarPart.ts | 4 +- .../parts/statusbar/media/statusbarpart.css | 12 + .../browser/parts/statusbar/statusbarPart.ts | 28 +- .../browser/parts/titlebar/menubarControl.ts | 47 +- .../browser/parts/titlebar/titlebarPart.ts | 6 +- .../browser/parts/views/customView.ts | 95 +- src/vs/workbench/browser/parts/views/views.ts | 14 +- .../browser/parts/views/viewsViewlet.ts | 2 +- src/vs/workbench/browser/web.main.ts | 27 +- .../workbench/browser/web.simpleservices.ts | 163 +- .../browser/workbench.contribution.ts | 2 +- .../{buildfile.js => buildfile.desktop.js} | 0 src/vs/workbench/buildfile.web.js | 25 + src/vs/workbench/common/composite.ts | 2 +- src/vs/workbench/common/editor.ts | 29 +- .../common/editor/dataUriEditorInput.ts | 5 +- .../common/editor/diffEditorInput.ts | 4 +- src/vs/workbench/common/editor/editorGroup.ts | 22 +- .../common/editor/resourceEditorInput.ts | 4 +- .../common/editor/textDiffEditorModel.ts | 14 +- .../common/editor/untitledEditorInput.ts | 8 +- src/vs/workbench/common/theme.ts | 8 +- src/vs/workbench/common/views.ts | 8 +- .../browser/callHierarchy.contribution.ts | 59 +- .../callHierarchy/browser/callHierarchy.ts | 84 + .../browser/callHierarchyPeek.ts | 182 +- .../browser/callHierarchyTree.ts | 93 +- .../browser/media/callHierarchy.css | 7 +- .../callHierarchy/common/callHierarchy.ts | 45 - .../contrib/cli/node/cli.contribution.ts | 31 +- .../browser/accessibility/accessibility.ts | 10 +- .../browser/find/simpleFindWidget.ts | 16 +- .../languageConfigurationExtensionPoint.ts | 4 +- .../codeEditor/browser/selectionClipboard.ts | 10 +- .../codeEditor/browser/toggleWordWrap.ts | 57 +- .../comments/browser/commentService.ts | 4 +- .../comments/browser/commentThreadWidget.ts | 11 +- .../browser/commentsEditorContribution.ts | 8 +- .../comments/browser/commentsTreeViewer.ts | 1 + .../contrib/customEditor/browser/commands.ts | 108 + .../customEditor/browser/customEditorInput.ts | 109 + .../browser/customEditorInputFactory.ts | 54 + .../customEditor/browser/customEditors.ts | 231 + .../customEditor/browser/extensionPoint.ts | 84 + .../browser/webviewEditor.contribution.ts | 69 + .../customEditor/common/customEditor.ts | 40 + .../contrib/debug/browser/baseDebugView.ts | 34 +- .../contrib/debug/browser/breakpointWidget.ts | 4 +- .../contrib/debug/browser/breakpointsView.ts | 38 +- .../contrib/debug/browser/callStackView.ts | 263 +- .../debug/browser/debug.contribution.ts | 95 +- .../debug/browser/debugActionViewItems.ts | 8 +- .../contrib/debug/browser/debugActions.ts | 6 +- .../contrib/debug/browser/debugCommands.ts | 13 +- .../debug/browser/debugEditorContribution.ts | 24 +- .../contrib/debug/browser/debugHover.ts | 18 +- .../contrib/debug/browser/debugService.ts | 62 +- .../contrib/debug/browser/debugSession.ts | 89 +- .../contrib/debug/browser/exceptionWidget.ts | 5 +- .../browser/extensionHostDebugService.ts | 16 +- .../contrib/debug/browser/linkDetector.ts | 12 +- .../debug/browser/loadedScriptsView.ts | 34 +- .../media/breakpoint-conditional-disabled.svg | 3 - .../breakpoint-conditional-unverified.svg | 3 - .../media/breakpoint-data-disabled.svg | 3 + .../media/breakpoint-data-unverified.svg | 3 + .../debug/browser/media/breakpoint-data.svg | 3 + .../debug/browser/media/continue-white.svg | 3 + .../browser/media/debug.contribution.css | 22 + .../debug/browser/media/debugViewlet.css | 117 + .../debug/browser/media/disconnect-white.svg | 3 + .../debug/browser/media/pause-white.svg | 3 + .../contrib/debug/browser/media/repl.css | 14 +- .../debug/browser/media/restart-white.svg | 3 + .../debug/browser/media/step-into-white.svg | 3 + .../debug/browser/media/step-out-white.svg | 3 + .../debug/browser/media/step-over-white.svg | 3 + .../debug/browser/media/stop-white.svg | 3 + .../contrib/debug/browser/rawDebugSession.ts | 77 +- .../workbench/contrib/debug/browser/repl.ts | 150 +- .../debug/browser/statusbarColorProvider.ts | 10 +- .../contrib/debug/browser/variablesView.ts | 14 +- .../debug/browser/watchExpressionsView.ts | 14 +- .../debug/common/abstractDebugAdapter.ts | 47 +- .../workbench/contrib/debug/common/debug.ts | 26 +- .../contrib/debug/common/debugModel.ts | 188 +- .../contrib/debug/common/debugProtocol.d.ts | 87 +- .../contrib/debug/common/debugSchemas.ts | 2 + .../contrib/debug/common/debugUtils.ts | 6 +- .../contrib/debug/common/debugViewModel.ts | 4 +- .../contrib/debug/common/replModel.ts | 103 +- .../contrib/debug/node/debugAdapter.ts | 13 +- .../contrib/debug/node/debugHelperService.ts | 2 +- .../debug/test/browser/baseDebugView.test.ts | 38 +- .../debug/test/browser/debugModel.test.ts | 10 +- .../contrib/debug/test/common/mockDebug.ts | 12 +- .../experiments/common/experimentService.ts | 6 +- .../extensions/browser/extensionEditor.ts | 2 +- .../browser/extensionTipsService.ts | 30 +- .../extensions/browser/extensionsActions.ts | 6 +- .../extensions/browser/extensionsViewer.ts | 1 + .../extensions/browser/extensionsViewlet.ts | 16 +- .../extensions/browser/extensionsViews.ts | 4 +- .../extensions/browser/extensionsWidgets.ts | 4 +- .../browser/extensionsWorkbenchService.ts | 2 +- .../browser/media/clear-inverse.svg | 1 - .../contrib/extensions/common/extensions.ts | 4 +- .../common/extensionsFileTemplate.ts | 3 +- .../extensionProfileService.ts | 2 +- .../extensions.contribution.ts | 17 +- .../runtimeExtensionsEditor.ts | 10 +- .../extensionsActions.test.ts | 4 +- .../extensionsTipsService.test.ts | 46 +- .../extensionsWorkbenchService.test.ts | 80 +- .../browser/externalTerminal.contribution.ts | 3 +- .../common/externalTerminal.ts | 2 +- .../node/externalTerminalService.ts | 8 +- .../contrib/feedback/browser/media/smiley.svg | 1 - .../files/browser/editors/binaryFileEditor.ts | 4 +- .../files/browser/editors/textFileEditor.ts | 31 +- .../contrib/files/browser/explorerViewlet.ts | 2 +- .../files/browser/fileActions.contribution.ts | 19 +- .../contrib/files/browser/fileActions.ts | 6 +- .../files/browser/media/action-close.svg | 1 - .../files/browser/media/close-all-hc.svg | 4 - .../contrib/files/browser/media/saveall.svg | 1 - .../files/browser/views/explorerView.ts | 88 +- .../files/browser/views/explorerViewer.ts | 30 +- .../files/browser/views/openEditorsView.ts | 8 +- .../files/common/editors/fileEditorInput.ts | 2 +- .../contrib/files/common/explorerService.ts | 6 +- .../workbench/contrib/files/common/files.ts | 3 +- .../contrib/issue/electron-browser/issue.ts | 2 +- .../issue/electron-browser/issueService.ts | 2 +- .../browser/localizations.contribution.ts | 1 + .../contrib/logs/common/logs.contribution.ts | 4 +- .../contrib/logs/common/logsActions.ts | 4 +- .../markers/browser/markers.contribution.ts | 5 +- .../contrib/markers/browser/markers.ts | 21 +- .../contrib/markers/browser/markersModel.ts | 71 +- .../contrib/markers/browser/markersPanel.ts | 191 +- .../markers/browser/markersPanelActions.ts | 45 +- .../markers/browser/markersTreeViewer.ts | 6 +- .../electron-browser/markersModel.test.ts | 2 +- .../contrib/outline/browser/outlinePanel.ts | 1 + .../contrib/output/browser/outputPanel.ts | 4 +- .../contrib/output/browser/outputServices.ts | 2 +- .../workbench/contrib/output/common/output.ts | 2 +- .../electron-browser/startupProfiler.ts | 7 +- .../preferences/browser/keybindingsEditor.ts | 4 +- .../browser/keybindingsEditorContribution.ts | 9 +- .../contrib/preferences/browser/media/add.svg | 1 - .../preferences/browser/media/add_inverse.svg | 1 - .../preferences/browser/media/clean-dark.svg | 1 - .../preferences/browser/media/clean.svg | 1 - .../browser/media/collapsed-dark.svg | 1 - .../preferences/browser/media/collapsed.svg | 1 - .../browser/media/edit-json-dark.svg | 3 - .../browser/media/edit-json-light.svg | 3 - .../preferences/browser/media/edit.svg | 1 - .../browser/media/edit_inverse.svg | 1 - .../browser/media/ellipsis-inverse.svg | 1 - .../preferences/browser/media/ellipsis.svg | 1 - .../browser/media/expanded-dark.svg | 1 - .../preferences/browser/media/expanded.svg | 1 - .../preferences/browser/media/keybindings.css | 18 - .../browser/media/open-file-inverse.svg | 1 - .../preferences/browser/media/open-file.svg | 1 - .../preferences/browser/media/regex-dark.svg | 1 - .../preferences/browser/media/regex.svg | 1 - .../browser/media/settingsEditor2.css | 1 + .../browser/preferences.contribution.ts | 27 +- .../preferences/browser/preferencesEditor.ts | 64 +- .../browser/preferencesRenderers.ts | 27 +- .../preferences/browser/preferencesSearch.ts | 2 +- .../preferences/browser/preferencesWidgets.ts | 90 +- .../preferences/browser/settingsEditor2.ts | 65 +- .../preferences/browser/settingsTree.ts | 6 +- .../preferences/browser/settingsTreeModels.ts | 76 +- .../preferences/browser/settingsWidgets.ts | 5 +- .../contrib/preferences/browser/tocTree.ts | 6 +- .../contrib/preferences/common/preferences.ts | 2 +- .../common/preferencesContribution.ts | 2 +- .../quickopen/browser/commandsHandler.ts | 14 +- .../quickopen/browser/gotoLineHandler.ts | 7 +- .../quickopen/browser/gotoSymbolHandler.ts | 10 +- .../quickopen/browser/viewPickerHandler.ts | 2 +- .../common/relauncher.contribution.ts | 18 +- .../contrib/remote/browser/remote.ts | 26 +- .../remote/common/remote.contribution.ts | 5 +- .../electron-browser/remote.contribution.ts | 4 +- .../browser/resourceServiceWorker.ts | 86 - .../browser/resourceServiceWorkerClient.ts | 49 - .../browser/resourceServiceWorkerMain.ts | 26 - .../contrib/scm/browser/dirtydiffDecorator.ts | 4 +- .../scm/browser/media/check-inverse.svg | 1 - .../contrib/scm/browser/media/check.svg | 1 - .../contrib/scm/browser/scmViewlet.ts | 119 +- src/vs/workbench/contrib/scm/common/scm.ts | 7 +- .../contrib/scm/common/scmService.ts | 2 +- .../search/browser/openAnythingHandler.ts | 10 +- .../contrib/search/browser/openFileHandler.ts | 14 +- .../search/browser/patternInputWidget.ts | 12 +- .../contrib/search/browser/replaceService.ts | 2 +- .../search/browser/search.contribution.ts | 4 +- .../contrib/search/browser/searchActions.ts | 26 +- .../search/browser/searchResultsView.ts | 10 +- .../contrib/search/browser/searchView.ts | 139 +- .../contrib/search/browser/searchWidget.ts | 39 +- .../contrib/search/common/constants.ts | 1 + .../contrib/search/common/replace.ts | 2 +- .../search/common/searchHistoryService.ts | 4 +- .../contrib/search/common/searchModel.ts | 98 +- .../search/test/browser/mockSearchTree.ts | 4 - .../search/test/common/searchModel.test.ts | 12 +- .../snippets/browser/snippets.contribution.ts | 4 +- .../snippets/browser/snippetsService.ts | 2 +- .../contrib/snippets/browser/tabCompletion.ts | 5 +- .../test/browser/snippetsService.test.ts | 2 +- .../stats/browser/workspaceStatsService.ts | 28 + .../contrib/stats/common/workspaceStats.ts | 2 +- .../electron-browser/workspaceStatsService.ts | 4 +- .../languageSurveys.contribution.ts | 2 +- .../tasks/browser/abstractTaskService.ts | 51 +- .../tasks/browser/task.contribution.ts | 2 + .../tasks/browser/terminalTaskSystem.ts | 44 +- .../contrib/tasks/common/jsonSchema_v2.ts | 1 + .../tasks/common/media/configure-hc.svg | 6 + .../tasks/common/media/task.contribution.css | 7 +- .../contrib/tasks/common/taskService.ts | 2 +- .../contrib/tasks/common/taskSystem.ts | 3 +- .../terminal/browser/media/terminal.css | 2 - .../terminal/browser/terminal.contribution.ts | 19 +- .../contrib/terminal/browser/terminal.ts | 410 +- .../terminal/browser/terminalActions.ts | 10 +- .../terminal/browser/terminalCommands.ts | 30 + .../terminal/browser/terminalConfigHelper.ts | 12 +- .../terminal/browser/terminalFindWidget.ts | 3 +- .../terminal/browser/terminalInstance.ts | 30 +- .../browser/terminalInstanceService.ts | 2 +- .../terminal/browser/terminalNativeService.ts | 2 +- .../contrib/terminal/browser/terminalPanel.ts | 3 +- .../terminalProcessExtHostProxy.ts | 3 +- .../browser/terminalProcessManager.ts | 4 +- .../terminal/browser/terminalQuickOpen.ts | 4 +- .../terminal/browser/terminalService.ts | 583 ++- .../contrib/terminal/browser/terminalTab.ts | 3 +- .../terminal/browser/xterm-private.d.ts | 34 + .../contrib/terminal/common/terminal.ts | 479 +- .../terminal/common/terminalCommands.ts | 96 - .../terminal/common/terminalEnvironment.ts | 72 +- .../contrib/terminal/common/terminalMenu.ts | 2 +- .../terminal/common/terminalService.ts | 595 --- .../terminalInstanceService.ts | 8 +- .../electron-browser/terminalNativeService.ts | 6 +- .../terminalRemote.ts | 4 +- .../windowsShellHelper.ts | 3 +- .../terminalCommandTracker.test.ts | 10 +- .../terminalLinkHandler.test.ts | 2 +- .../test/node/terminalEnvironment.test.ts | 154 +- .../media/code-icon.svg | 0 .../media/markdown.css | 0 .../releaseNotesEditor.ts | 18 +- .../update/browser/update.contribution.ts | 21 + .../contrib/update/browser/update.ts | 474 ++ .../electron-browser/update.contribution.ts | 13 +- .../contrib/update/electron-browser/update.ts | 469 +- .../contrib/url/common/url.contribution.ts | 95 +- .../contrib/watermark/browser/watermark.ts | 2 +- .../browser/dynamicWebviewEditorOverlay.ts | 7 +- .../contrib/webview/browser/pre/main.js | 29 +- .../contrib/webview/browser/webview.ts | 3 +- .../contrib/webview/browser/webviewEditor.ts | 33 +- .../webview/browser/webviewEditorInput.ts | 14 +- .../browser/webviewEditorInputFactory.ts | 59 +- .../webview/browser/webviewEditorService.ts | 71 +- .../contrib/webview/browser/webviewElement.ts | 47 +- .../webview/browser/webviewFindWidget.ts | 6 + .../contrib/webview/browser/webviewService.ts | 2 +- .../electron-browser/webviewElement.ts | 21 +- .../electron-browser/webviewService.ts | 2 +- .../electron-browser/telemetryOptOut.ts | 30 +- .../welcome/overlay/browser/welcomeOverlay.ts | 2 +- .../walkThrough/browser/walkThroughPart.ts | 8 +- .../electron-browser/actions/helpActions.ts | 38 +- .../electron-browser/desktop.contribution.ts | 163 +- src/vs/workbench/electron-browser/window.ts | 52 +- .../node/accessibilityService.ts | 3 +- .../activity/browser/activityService.ts | 2 +- .../services/activity/common/activity.ts | 2 +- .../activityBar/browser/activityBarService.ts | 2 +- .../services/backup/common/backup.ts | 6 +- .../backup/common/backupFileService.ts | 17 +- .../test/node/backupFileService.test.ts | 4 +- .../bulkEdit/browser/bulkEditService.ts | 5 +- .../commands/common/commandService.ts | 2 +- .../browser/configurationService.ts | 33 +- .../common/configurationEditingService.ts | 2 +- .../configuration/common/jsonEditing.ts | 6 +- .../common/jsonEditingService.ts | 2 +- .../configurationEditingService.test.ts | 6 +- .../configurationService.test.ts | 136 +- .../browser/configurationResolverService.ts | 14 +- .../common/configurationResolver.ts | 10 +- .../common/variableResolver.ts | 82 +- .../configurationResolverService.test.ts | 19 +- .../electron-browser/contextmenuService.ts | 4 +- .../credentials/browser/credentialsService.ts | 112 +- .../credentials/common/credentials.ts | 5 +- .../credentials/node/credentialsService.ts | 16 +- .../decorations/browser/decorations.ts | 6 +- .../decorations/browser/decorationsService.ts | 37 +- .../test/browser/decorationsService.test.ts | 26 - .../dialogs/browser/fileDialogService.ts | 40 +- .../dialogs/browser/remoteFileDialog.ts | 16 +- .../dialogs/electron-browser/dialogService.ts | 16 +- .../services/editor/browser/editorService.ts | 12 +- .../editor/common/editorGroupsService.ts | 4 +- .../services/editor/common/editorService.ts | 4 +- .../test/browser/editorGroupsService.test.ts | 2 +- .../editor/test/browser/editorService.test.ts | 47 +- .../environment/browser/environmentService.ts | 3 +- .../environment/common/environmentService.ts | 4 +- .../environment/node/environmentService.ts | 3 +- .../common/extensionEnablementService.ts | 2 +- .../common/extensionManagement.ts | 6 +- .../extensionManagementServerService.ts | 2 +- .../common/extensionManagementService.ts | 2 +- .../extensionManagementServerService.ts | 2 +- .../extensionEnablementService.test.ts | 2 +- .../browser/webWorkerExtensionHostStarter.ts | 2 +- .../common/abstractExtensionService.ts | 15 +- ...onUrlHandler.ts => extensionUrlHandler.ts} | 45 +- .../services/extensions/common/extensions.ts | 4 +- .../extensions/common/staticExtensions.ts | 4 +- .../remoteExtensionManagementIpc.ts | 2 +- .../extensions/node/extensionPoints.ts | 11 +- .../services/extensions/node/proxyResolver.ts | 36 +- .../extensions/worker/extHost.services.ts | 4 +- .../extensions/worker/extensionHostWorker.ts | 5 +- .../services/history/browser/history.ts | 6 +- .../services/history/common/history.ts | 4 +- .../integrity/browser/integrityService.ts | 3 +- .../services/integrity/common/integrity.ts | 2 +- .../integrity/node/integrityService.ts | 45 +- .../keybinding/browser/keybindingService.ts | 14 +- .../keybinding/browser/keymapService.ts | 2 +- .../keybinding/common/keybindingEditing.ts | 8 +- .../services/keybinding/common/keymapInfo.ts | 4 +- .../common/windowsKeyboardMapper.ts | 27 + .../electron-browser/nativeKeymapService.ts | 2 +- .../keybindingEditing.test.ts | 4 +- .../test/keyboardMapperTestUtils.ts | 2 +- .../macLinuxFallbackKeyboardMapper.test.ts | 16 +- .../test/macLinuxKeyboardMapper.test.ts | 16 +- .../services/keybinding/test/win_ru.txt | 64 +- .../test/windowsKeyboardMapper.test.ts | 16 +- .../services/label/common/labelService.ts | 9 +- .../services/layout/browser/layoutService.ts | 9 +- .../common/notificationService.ts | 3 +- .../output/common/outputChannelModel.ts | 2 +- .../common/outputChannelModelService.ts | 2 +- .../output/node/outputChannelModelService.ts | 2 +- .../services/panel/common/panelService.ts | 4 +- .../preferences/browser/preferencesService.ts | 4 +- .../preferences/common/preferences.ts | 2 +- .../common/preferencesEditorInput.ts | 4 +- .../preferences/common/preferencesModels.ts | 7 + .../test/common/preferencesModel.test.ts | 6 + .../progress/browser/editorProgressService.ts | 4 +- .../progress/browser/progressService.ts | 7 +- .../remote/browser/remoteAgentServiceImpl.ts | 5 +- .../common/abstractRemoteAgentService.ts | 2 +- .../common/remoteAgentEnvironmentChannel.ts | 2 +- .../remote/common/remoteAgentService.ts | 2 +- .../services/remote/node/tunnelService.ts | 2 +- .../services/search/common/replace.ts | 2 +- .../services/search/common/search.ts | 5 +- .../services/search/common/searchExtTypes.ts | 6 +- .../services/search/common/searchService.ts | 5 +- .../services/search/node/fileSearch.ts | 24 +- .../services/search/node/rawSearchService.ts | 2 +- .../search/node/ripgrepTextSearchEngine.ts | 29 +- .../services/search/node/textSearchManager.ts | 14 +- .../search/test/node/rawSearchService.test.ts | 19 + .../test/node/ripgrepTextSearchEngine.test.ts | 7 +- .../test/node/textSearch.integrationTest.ts | 20 + .../telemetry/browser/telemetryService.ts | 2 +- .../electron-browser/telemetryService.ts | 4 +- .../browser/abstractTextMateService.ts | 53 +- .../textMate/browser/textMateService.ts | 17 +- .../textMate/common/textMateService.ts | 2 +- .../textfile/common/textFileService.ts | 13 +- .../common/textResourcePropertiesService.ts | 3 +- .../services/textfile/common/textfiles.ts | 6 +- .../common/textModelResolverService.ts | 2 +- .../themes/browser/workbenchThemeService.ts | 2 +- .../themes/common/colorThemeSchema.ts | 1 + .../themes/common/fileIconThemeSchema.ts | 3 +- .../themes/common/workbenchThemeService.ts | 2 +- .../timer/electron-browser/timerService.ts | 4 +- .../services/title/common/titleService.ts | 2 +- .../untitled/common/untitledEditorService.ts | 6 +- .../services/update/browser/updateService.ts | 95 + .../services/url/browser/urlService.ts | 129 +- .../url/electron-browser/urlService.ts | 23 +- .../services/viewlet/browser/viewlet.ts | 4 +- .../window/electron-browser/windowService.ts | 2 +- .../workspaceEditingService.ts | 20 +- .../workspace/common/workspaceEditing.ts | 6 +- .../browser/parts/editor/baseEditor.test.ts | 2 +- .../workbench/test/browser/quickopen.test.ts | 2 +- .../test/contrib/linkProtection.test.ts | 42 + .../api/extHostApiCommands.test.ts | 31 +- .../api/extHostCommands.test.ts | 31 + .../api/extHostMessagerService.test.ts | 13 +- .../api/mainThreadCommands.test.ts | 50 +- .../api/mainThreadDocumentsAndEditors.test.ts | 2 +- .../api/mainThreadEditors.test.ts | 2 +- .../electron-browser/api/testRPCProtocol.ts | 2 +- .../colorRegistry.releaseTest.ts | 25 +- .../quickopen.perf.integrationTest.ts | 2 +- .../textsearch.perf.integrationTest.ts | 2 +- .../workbench/test/workbenchTestServices.ts | 55 +- src/vs/workbench/workbench.common.main.ts | 8 +- src/vs/workbench/workbench.desktop.main.ts | 2 +- src/vs/workbench/workbench.web.api.ts | 21 +- src/vs/workbench/workbench.web.main.ts | 8 +- test/automation/.gitignore | 7 + test/automation/README.md | 3 + test/automation/package.json | 40 + .../src}/activityBar.ts | 4 +- test/{smoke => automation}/src/application.ts | 12 +- .../src/vscode => automation/src}/code.ts | 13 +- .../debugSmoke.ts => automation/src/debug.ts} | 20 +- .../src/vscode => automation/src}/driver.js | 0 .../areas/editor => automation/src}/editor.ts | 12 +- .../editor => automation/src}/editors.ts | 4 +- .../explorer => automation/src}/explorer.ts | 8 +- .../src}/extensions.ts | 6 +- test/automation/src/index.ts | 34 + .../src}/keybindings.ts | 4 +- test/{smoke => automation}/src/logger.ts | 0 .../areas/editor => automation/src}/peek.ts | 2 +- .../problems => automation/src}/problems.ts | 2 +- .../src}/puppeteerDriver.ts | 56 +- .../src}/quickinput.ts | 2 +- .../quickopen => automation/src}/quickopen.ts | 4 +- .../src/areas/git => automation/src}/scm.ts | 8 +- .../areas/search => automation/src}/search.ts | 6 +- .../src}/settings.ts | 13 +- .../src/sql}/connectionDialog.ts | 8 +- .../src/sql}/profiler.ts | 8 +- .../src/sql}/queryEditors.ts | 6 +- .../{smoke => automation}/src/sql/sqlutils.ts | 4 +- .../src/sql/testConfig.ts | 4 +- .../statusbar => automation/src}/statusbar.ts | 2 +- .../terminal => automation/src}/terminal.ts | 6 +- .../workbench => automation/src}/viewlet.ts | 4 +- .../workbench => automation/src}/workbench.ts | 38 +- .../tools/copy-driver-definition.js | 7 +- test/automation/tools/copy-package-version.js | 19 + test/automation/tsconfig.json | 21 + test/automation/yarn.lock | 1842 ++++++++ test/electron/renderer.html | 6 +- test/smoke/README.md | 8 +- test/smoke/package.json | 14 +- test/smoke/src/areas/css/css.test.ts | 5 +- test/smoke/src/areas/debug/debug.test.ts | 2 +- test/smoke/src/areas/editor/editor.test.ts | 4 +- .../smoke/src/areas/explorer/explorer.test.ts | 4 +- .../src/areas/extensions/extensions.test.ts | 4 +- test/smoke/src/areas/git/git.test.ts | 4 +- .../src/areas/multiroot/multiroot.test.ts | 7 +- .../src/areas/preferences/preferences.test.ts | 3 +- test/smoke/src/areas/search/search.test.ts | 4 +- .../src/areas/statusbar/statusbar.test.ts | 5 +- .../smoke/src/areas/terminal/terminal.test.ts | 2 +- .../src/areas/workbench/data-loss.test.ts | 2 +- .../areas/workbench/data-migration.test.ts | 2 +- test/smoke/src/areas/workbench/launch.test.ts | 4 +- .../src/areas/workbench/localization.test.ts | 2 +- test/smoke/src/main.ts | 15 +- test/smoke/src/sql/profiler/profiler.test.ts | 5 +- .../src/sql/queryEditor/queryEditor.test.ts | 4 +- test/smoke/tsconfig.json | 4 +- test/smoke/yarn.lock | 861 +--- test/tree/public/index.html | 33 +- yarn.lock | 1132 +---- 1226 files changed, 21541 insertions(+), 17633 deletions(-) create mode 100644 .prettierrc.json create mode 100755 build/azure-pipelines/common/publish-webview.sh create mode 100644 build/azure-pipelines/common/publish-webview.ts rename extensions/admin-tool-ext-win/{src => }/config.json (100%) create mode 100644 extensions/image-preview/.vscodeignore create mode 100644 extensions/image-preview/README.md create mode 100644 extensions/image-preview/extension.webpack.config.js create mode 100644 extensions/image-preview/media/main.css create mode 100644 extensions/image-preview/media/main.js create mode 100644 extensions/image-preview/package.json create mode 100644 extensions/image-preview/package.nls.json create mode 100644 extensions/image-preview/src/dispose.ts create mode 100644 extensions/image-preview/src/extension.ts create mode 100644 extensions/image-preview/src/preview.ts create mode 100644 extensions/image-preview/src/sizeStatusBarEntry.ts create mode 100644 extensions/image-preview/src/typings/ref.d.ts create mode 100644 extensions/image-preview/src/zoomStatusBarEntry.ts create mode 100644 extensions/image-preview/tsconfig.json create mode 100644 extensions/image-preview/yarn.lock rename extensions/import/{src/services => }/config.json (100%) create mode 100644 extensions/markdown-language-features/src/docIndex.ts rename extensions/mssql/{src => }/config.json (100%) rename scripts/{test-release.bat => test-documentation.bat} (66%) rename scripts/{test-release.sh => test-documentation.sh} (79%) delete mode 100644 src/vs/base/browser/ui/octiconLabel/octicons/octicons2.svg delete mode 100644 src/vs/base/browser/ui/tree/compressedObjectTree.ts create mode 100644 src/vs/code/browser/workbench/callback.html create mode 100644 src/vs/code/browser/workbench/workbench-dev.html delete mode 100644 src/vs/code/browser/workbench/workbench.js create mode 100644 src/vs/code/browser/workbench/workbench.ts create mode 100644 src/vs/platform/product/browser/product.ts rename src/vs/platform/remote/{node => common}/tunnelService.ts (72%) delete mode 100644 src/vs/platform/telemetry/node/telemetryNodeUtils.ts rename src/vs/platform/update/{node => common}/update.config.contribution.ts (96%) rename src/vs/platform/update/{node => electron-main}/updateIpc.ts (100%) rename src/vs/platform/url/{node => common}/urlIpc.ts (64%) delete mode 100644 src/vs/workbench/browser/parts/editor/media/close-dirty-inverse-alt.svg delete mode 100644 src/vs/workbench/browser/parts/editor/media/close-dirty-inverse.svg rename src/vs/workbench/{buildfile.js => buildfile.desktop.js} (100%) create mode 100644 src/vs/workbench/buildfile.web.js create mode 100644 src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.ts delete mode 100644 src/vs/workbench/contrib/callHierarchy/common/callHierarchy.ts create mode 100644 src/vs/workbench/contrib/customEditor/browser/commands.ts create mode 100644 src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts create mode 100644 src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts create mode 100644 src/vs/workbench/contrib/customEditor/browser/customEditors.ts create mode 100644 src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts create mode 100644 src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts create mode 100644 src/vs/workbench/contrib/customEditor/common/customEditor.ts delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional-disabled.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional-unverified.svg create mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-data-disabled.svg create mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-data-unverified.svg create mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-data.svg create mode 100644 src/vs/workbench/contrib/debug/browser/media/continue-white.svg create mode 100644 src/vs/workbench/contrib/debug/browser/media/disconnect-white.svg create mode 100644 src/vs/workbench/contrib/debug/browser/media/pause-white.svg create mode 100644 src/vs/workbench/contrib/debug/browser/media/restart-white.svg create mode 100644 src/vs/workbench/contrib/debug/browser/media/step-into-white.svg create mode 100644 src/vs/workbench/contrib/debug/browser/media/step-out-white.svg create mode 100644 src/vs/workbench/contrib/debug/browser/media/step-over-white.svg create mode 100644 src/vs/workbench/contrib/debug/browser/media/stop-white.svg delete mode 100644 src/vs/workbench/contrib/extensions/browser/media/clear-inverse.svg delete mode 100644 src/vs/workbench/contrib/feedback/browser/media/smiley.svg delete mode 100644 src/vs/workbench/contrib/files/browser/media/action-close.svg delete mode 100644 src/vs/workbench/contrib/files/browser/media/close-all-hc.svg delete mode 100644 src/vs/workbench/contrib/files/browser/media/saveall.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/add.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/add_inverse.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/clean-dark.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/clean.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/collapsed-dark.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/collapsed.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/edit-json-dark.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/edit-json-light.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/edit.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/edit_inverse.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/ellipsis-inverse.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/ellipsis.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/expanded-dark.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/expanded.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/open-file-inverse.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/open-file.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/regex-dark.svg delete mode 100644 src/vs/workbench/contrib/preferences/browser/media/regex.svg delete mode 100644 src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts delete mode 100644 src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts delete mode 100644 src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts delete mode 100644 src/vs/workbench/contrib/scm/browser/media/check-inverse.svg delete mode 100644 src/vs/workbench/contrib/scm/browser/media/check.svg create mode 100644 src/vs/workbench/contrib/stats/browser/workspaceStatsService.ts create mode 100644 src/vs/workbench/contrib/tasks/common/media/configure-hc.svg create mode 100644 src/vs/workbench/contrib/terminal/browser/terminalCommands.ts rename src/vs/workbench/contrib/terminal/{common => browser}/terminalProcessExtHostProxy.ts (95%) create mode 100644 src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts delete mode 100644 src/vs/workbench/contrib/terminal/common/terminalCommands.ts delete mode 100644 src/vs/workbench/contrib/terminal/common/terminalService.ts rename src/vs/workbench/contrib/terminal/{node => electron-browser}/terminalRemote.ts (90%) rename src/vs/workbench/contrib/terminal/{node => electron-browser}/windowsShellHelper.ts (95%) rename src/vs/workbench/contrib/update/{electron-browser => browser}/media/code-icon.svg (100%) rename src/vs/workbench/contrib/update/{electron-browser => browser}/media/markdown.css (100%) rename src/vs/workbench/contrib/update/{electron-browser => browser}/releaseNotesEditor.ts (90%) create mode 100644 src/vs/workbench/contrib/update/browser/update.contribution.ts create mode 100644 src/vs/workbench/contrib/update/browser/update.ts rename src/vs/workbench/services/extensions/common/{inactiveExtensionUrlHandler.ts => extensionUrlHandler.ts} (91%) create mode 100644 src/vs/workbench/services/update/browser/updateService.ts rename src/vs/workbench/services/workspace/{electron-browser => browser}/workspaceEditingService.ts (96%) create mode 100644 src/vs/workbench/test/contrib/linkProtection.test.ts create mode 100644 test/automation/.gitignore create mode 100644 test/automation/README.md create mode 100644 test/automation/package.json rename test/{smoke/src/areas/activitybar => automation/src}/activityBar.ts (95%) rename test/{smoke => automation}/src/application.ts (90%) rename test/{smoke/src/vscode => automation/src}/code.ts (97%) rename test/{smoke/src/areas/debug/debugSmoke.ts => automation/src/debug.ts} (90%) rename test/{smoke/src/vscode => automation/src}/driver.js (100%) rename test/{smoke/src/areas/editor => automation/src}/editor.ts (94%) rename test/{smoke/src/areas/editor => automation/src}/editors.ts (97%) rename test/{smoke/src/areas/explorer => automation/src}/explorer.ts (92%) rename test/{smoke/src/areas/extensions => automation/src}/extensions.ts (94%) create mode 100644 test/automation/src/index.ts rename test/{smoke/src/areas/preferences => automation/src}/keybindings.ts (97%) rename test/{smoke => automation}/src/logger.ts (100%) rename test/{smoke/src/areas/editor => automation/src}/peek.ts (97%) rename test/{smoke/src/areas/problems => automation/src}/problems.ts (97%) rename test/{smoke/src/vscode => automation/src}/puppeteerDriver.ts (67%) rename test/{smoke/src/areas/quickinput => automation/src}/quickinput.ts (97%) rename test/{smoke/src/areas/quickopen => automation/src}/quickopen.ts (97%) rename test/{smoke/src/areas/git => automation/src}/scm.ts (94%) rename test/{smoke/src/areas/search => automation/src}/search.ts (95%) rename test/{smoke/src/areas/preferences => automation/src}/settings.ts (84%) rename test/{smoke/src/sql/connectionDialog => automation/src/sql}/connectionDialog.ts (92%) rename test/{smoke/src/sql/profiler => automation/src/sql}/profiler.ts (83%) rename test/{smoke/src/sql/queryEditor => automation/src/sql}/queryEditors.ts (93%) rename test/{smoke => automation}/src/sql/sqlutils.ts (94%) rename test/{smoke => automation}/src/sql/testConfig.ts (97%) rename test/{smoke/src/areas/statusbar => automation/src}/statusbar.ts (98%) rename test/{smoke/src/areas/terminal => automation/src}/terminal.ts (93%) rename test/{smoke/src/areas/workbench => automation/src}/viewlet.ts (93%) rename test/{smoke/src/areas/workbench => automation/src}/workbench.ts (68%) rename test/{smoke => automation}/tools/copy-driver-definition.js (90%) create mode 100644 test/automation/tools/copy-package-version.js create mode 100644 test/automation/tsconfig.json create mode 100644 test/automation/yarn.lock diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000000..91855cc846 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "useTabs": true, + "printWidth": 120, + "semi": true, + "singleQuote": true +} diff --git a/.yarnrc b/.yarnrc index 98712ee2b4..ff946c7a25 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://atom.io/download/electron" -target "4.2.9" +target "4.2.10" runtime "electron" diff --git a/build/.cachesalt b/build/.cachesalt index 105ce86ae3..339d2d379f 100644 --- a/build/.cachesalt +++ b/build/.cachesalt @@ -1 +1 @@ -2019-07-11T05:47:05.444Z +2019-08-30T20:24:23.714Z diff --git a/build/azure-pipelines/common/publish-webview.sh b/build/azure-pipelines/common/publish-webview.sh new file mode 100755 index 0000000000..77e222258f --- /dev/null +++ b/build/azure-pipelines/common/publish-webview.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -e +REPO="$(pwd)" + +# Publish webview contents +PACKAGEJSON="$REPO/package.json" +VERSION=$(node -p "require(\"$PACKAGEJSON\").version") + +node build/azure-pipelines/common/publish-webview.js "$REPO/src/vs/workbench/contrib/webview/browser/pre/" diff --git a/build/azure-pipelines/common/publish-webview.ts b/build/azure-pipelines/common/publish-webview.ts new file mode 100644 index 0000000000..852c12f98a --- /dev/null +++ b/build/azure-pipelines/common/publish-webview.ts @@ -0,0 +1,87 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as azure from 'azure-storage'; +import * as mime from 'mime'; +import * as minimist from 'minimist'; +import { basename, join } from 'path'; + +const fileNames = [ + 'fake.html', + 'host.js', + 'index.html', + 'main.js', + 'service-worker.js' +]; + +async function assertContainer(blobService: azure.BlobService, container: string): Promise { + await new Promise((c, e) => blobService.createContainerIfNotExists(container, { publicAccessLevel: 'blob' }, err => err ? e(err) : c())); +} + +async function doesBlobExist(blobService: azure.BlobService, container: string, blobName: string): Promise { + const existsResult = await new Promise((c, e) => blobService.doesBlobExist(container, blobName, (err, r) => err ? e(err) : c(r))); + return existsResult.exists; +} + +async function uploadBlob(blobService: azure.BlobService, container: string, blobName: string, file: string): Promise { + const blobOptions: azure.BlobService.CreateBlockBlobRequestOptions = { + contentSettings: { + contentType: mime.lookup(file), + cacheControl: 'max-age=31536000, public' + } + }; + + await new Promise((c, e) => blobService.createBlockBlobFromLocalFile(container, blobName, file, blobOptions, err => err ? e(err) : c())); +} + +async function publish(commit: string, files: readonly string[]): Promise { + + console.log('Publishing...'); + console.log('Commit:', commit); + const storageAccount = process.env['AZURE_WEBVIEW_STORAGE_ACCOUNT']!; + + const blobService = azure.createBlobService(storageAccount, process.env['AZURE_WEBVIEW_STORAGE_ACCESS_KEY']!) + .withFilter(new azure.ExponentialRetryPolicyFilter(20)); + + await assertContainer(blobService, commit); + + for (const file of files) { + const blobName = basename(file); + const blobExists = await doesBlobExist(blobService, commit, blobName); + if (blobExists) { + console.log(`Blob ${commit}, ${blobName} already exists, not publishing again.`); + continue; + } + console.log('Uploading blob to Azure storage...'); + await uploadBlob(blobService, commit, blobName, file); + } + + console.log('Blobs successfully uploaded.'); +} + +function main(): void { + const commit = process.env['BUILD_SOURCEVERSION']; + + if (!commit) { + console.warn('Skipping publish due to missing BUILD_SOURCEVERSION'); + return; + } + + const opts = minimist(process.argv.slice(2)); + const [directory] = opts._; + + const files = fileNames.map(fileName => join(directory, fileName)); + + publish(commit, files).catch(err => { + console.error(err); + process.exit(1); + }); +} + +if (process.argv.length < 3) { + console.error('Usage: node publish.js '); + process.exit(-1); +} +main(); diff --git a/build/azure-pipelines/darwin/continuous-build-darwin.yml b/build/azure-pipelines/darwin/continuous-build-darwin.yml index fcbd3c3037..ef636f91e9 100644 --- a/build/azure-pipelines/darwin/continuous-build-darwin.yml +++ b/build/azure-pipelines/darwin/continuous-build-darwin.yml @@ -9,7 +9,7 @@ steps: vstsFeed: '$(ArtifactFeed)' - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: - versionSpec: "1.10.1" + versionSpec: "1.x" - script: | yarn --frozen-lockfile displayName: Install Dependencies @@ -24,8 +24,11 @@ steps: yarn gulp electron-x64 displayName: Download Electron - script: | - yarn gulp hygiene + yarn gulp hygiene --skip-tslint displayName: Run Hygiene Checks +- script: | + yarn gulp tslint + displayName: Run TSLint Checks - script: | yarn monaco-compile-check displayName: Run Monaco Editor Checks diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 01f5420843..0616a2d4dd 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -25,7 +25,7 @@ steps: - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: - versionSpec: "1.10.1" + versionSpec: "1.x" - task: AzureKeyVault@1 displayName: 'Azure Key Vault: Get Secrets' @@ -102,20 +102,28 @@ steps: condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - script: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. set -e + APP_ROOT=$(agent.builddirectory)/VSCode-darwin + APP_NAME="`ls $APP_ROOT | head -n 1`" + INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \ + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin" \ ./scripts/test-integration.sh --build --tfs "Integration Tests" displayName: Run integration tests condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - set -e - cd test/smoke - yarn compile - cd - - yarn smoketest --web --headless - continueOnError: true - displayName: Run web smoke tests - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) +# Web Smoke Tests disabled due to https://github.com/microsoft/vscode/issues/80308 +# - script: | +# set -e +# cd test/smoke +# yarn compile +# cd - +# yarn smoketest --web --headless +# continueOnError: true +# displayName: Run web smoke tests +# condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - script: | set -e diff --git a/build/azure-pipelines/exploration-build.yml b/build/azure-pipelines/exploration-build.yml index b1cce331c4..39a8f23b26 100644 --- a/build/azure-pipelines/exploration-build.yml +++ b/build/azure-pipelines/exploration-build.yml @@ -1,6 +1,13 @@ pool: vmImage: 'Ubuntu-16.04' +trigger: + branches: + include: ['master'] +pr: + branches: + include: ['master'] + steps: - task: NodeTool@0 inputs: @@ -31,13 +38,3 @@ steps: git push origin HEAD:electron-6.0.x displayName: Sync & Merge Exploration - -trigger: none -pr: none - -schedules: -- cron: "0 5 * * Mon-Fri" - displayName: Mon-Fri at 7:00 - branches: - include: - - master diff --git a/build/azure-pipelines/linux/continuous-build-linux.yml b/build/azure-pipelines/linux/continuous-build-linux.yml index 8b0aaca2ad..d71ab286b1 100644 --- a/build/azure-pipelines/linux/continuous-build-linux.yml +++ b/build/azure-pipelines/linux/continuous-build-linux.yml @@ -17,7 +17,7 @@ steps: vstsFeed: '$(ArtifactFeed)' - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: - versionSpec: "1.10.1" + versionSpec: "1.x" - script: | yarn --frozen-lockfile displayName: Install Dependencies @@ -32,8 +32,11 @@ steps: yarn gulp electron-x64 displayName: Download Electron - script: | - yarn gulp hygiene + yarn gulp hygiene --skip-tslint displayName: Run Hygiene Checks +- script: | + yarn gulp tslint + displayName: Run TSLint Checks - script: | yarn monaco-compile-check displayName: Run Monaco Editor Checks diff --git a/build/azure-pipelines/linux/product-build-linux-multiarch.yml b/build/azure-pipelines/linux/product-build-linux-multiarch.yml index d36c115be7..4f5e39dcdf 100644 --- a/build/azure-pipelines/linux/product-build-linux-multiarch.yml +++ b/build/azure-pipelines/linux/product-build-linux-multiarch.yml @@ -25,7 +25,7 @@ steps: - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: - versionSpec: "1.10.1" + versionSpec: "1.x" - task: AzureKeyVault@1 displayName: 'Azure Key Vault: Get Secrets' diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index a6cc1c3496..0d01ba8a60 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -25,7 +25,7 @@ steps: - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: - versionSpec: "1.10.1" + versionSpec: "1.x" - task: AzureKeyVault@1 displayName: 'Azure Key Vault: Get Secrets' @@ -105,7 +105,14 @@ steps: condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - script: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. set -e + APP_ROOT=$(agent.builddirectory)/VSCode-linux-x64 + APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName") + INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \ + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-x64" \ DISPLAY=:10 ./scripts/test-integration.sh --build --tfs "Integration Tests" # yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-x64" displayName: Run integration tests diff --git a/build/azure-pipelines/linux/snap-build-linux.yml b/build/azure-pipelines/linux/snap-build-linux.yml index 4c3f602e8c..047081ced0 100644 --- a/build/azure-pipelines/linux/snap-build-linux.yml +++ b/build/azure-pipelines/linux/snap-build-linux.yml @@ -5,7 +5,7 @@ steps: - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: - versionSpec: "1.10.1" + versionSpec: "1.x" - task: AzureKeyVault@1 displayName: 'Azure Key Vault: Get Secrets' @@ -51,4 +51,4 @@ steps: # Publish snap package AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-x64" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH" \ No newline at end of file + node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-x64" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH" diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index f38f431182..ecf47fa1cd 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -56,7 +56,7 @@ jobs: - template: linux/snap-build-linux.yml - job: LinuxArmhf - condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable')) + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true')) pool: vmImage: 'Ubuntu-16.04' variables: @@ -78,7 +78,7 @@ jobs: - template: linux/product-build-linux-multiarch.yml - job: LinuxAlpine - condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable')) + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true')) pool: vmImage: 'Ubuntu-16.04' variables: diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 169dfe154f..76e1f6a927 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -20,7 +20,7 @@ steps: - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: - versionSpec: "1.10.1" + versionSpec: "1.x" condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) - task: AzureKeyVault@1 @@ -87,9 +87,10 @@ steps: - script: | set -e - yarn gulp hygiene + yarn gulp hygiene --skip-tslint + yarn gulp tslint yarn monaco-compile-check - displayName: Run hygiene checks + displayName: Run hygiene, tslint and monaco compile checks condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - script: | @@ -98,6 +99,13 @@ steps: displayName: Extract Telemetry condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) +- script: | + set -e + AZURE_WEBVIEW_STORAGE_ACCESS_KEY="$(vscode-webview-storage-key)" \ + ./build/azure-pipelines/common/publish-webview.sh + displayName: Publish Webview + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + - script: | set -e yarn gulp compile-build diff --git a/build/azure-pipelines/publish-types/publish-types.yml b/build/azure-pipelines/publish-types/publish-types.yml index ff03cecedb..6808054b3f 100644 --- a/build/azure-pipelines/publish-types/publish-types.yml +++ b/build/azure-pipelines/publish-types/publish-types.yml @@ -13,7 +13,23 @@ steps: - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: - versionSpec: "1.10.1" + versionSpec: "1.x" + +- bash: | + TAG_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`) + CHANNEL="G1C14HJ2F" + + if [ "$TAG_VERSION" == "1.999.0" ]; then + MESSAGE=". Someone pushed 1.999.0 tag. Please delete it ASAP from remote and local." + + curl -X POST -H "Authorization: Bearer $(SLACK_TOKEN)" \ + -H 'Content-type: application/json; charset=utf-8' \ + --data '{"channel":"'"$CHANNEL"'", "link_names": true, "text":"'"$MESSAGE"'"}' \ + https://slack.com/api/chat.postMessage + + exit 1 + fi + displayName: Check 1.999.0 tag - bash: | # Install build dependencies diff --git a/build/azure-pipelines/sync-mooncake.yml b/build/azure-pipelines/sync-mooncake.yml index f3e8bc0785..1fb8ffcd88 100644 --- a/build/azure-pipelines/sync-mooncake.yml +++ b/build/azure-pipelines/sync-mooncake.yml @@ -5,7 +5,7 @@ steps: - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: - versionSpec: "1.10.1" + versionSpec: "1.x" - task: AzureKeyVault@1 displayName: 'Azure Key Vault: Get Secrets' diff --git a/build/azure-pipelines/web/product-build-web.yml b/build/azure-pipelines/web/product-build-web.yml index fe5231dacc..46ecb39eac 100644 --- a/build/azure-pipelines/web/product-build-web.yml +++ b/build/azure-pipelines/web/product-build-web.yml @@ -25,7 +25,7 @@ steps: - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: - versionSpec: "1.10.1" + versionSpec: "1.x" - task: AzureKeyVault@1 displayName: 'Azure Key Vault: Get Secrets' diff --git a/build/azure-pipelines/win32/continuous-build-win32.yml b/build/azure-pipelines/win32/continuous-build-win32.yml index 9b6d61ee97..f9b1130d24 100644 --- a/build/azure-pipelines/win32/continuous-build-win32.yml +++ b/build/azure-pipelines/win32/continuous-build-win32.yml @@ -4,7 +4,7 @@ steps: versionSpec: "10.15.1" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: - versionSpec: "1.10.1" + versionSpec: "1.x" - task: UsePythonVersion@0 inputs: versionSpec: '2.x' @@ -26,10 +26,12 @@ steps: condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) - powershell: | yarn gulp electron - displayName: Download Electron -- powershell: | - yarn gulp hygiene +- script: | + yarn gulp hygiene --skip-tslint displayName: Run Hygiene Checks +- script: | + yarn gulp tslint + displayName: Run TSLint Checks - powershell: | yarn monaco-compile-check displayName: Run Monaco Editor Checks diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 71a47e63d4..ae36c8cbe8 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -25,7 +25,7 @@ steps: - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: - versionSpec: "1.10.1" + versionSpec: "1.x" - task: UsePythonVersion@0 inputs: @@ -113,10 +113,15 @@ steps: condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - powershell: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - exec { yarn gulp "electron-$(VSCODE_ARCH)" } - exec { .\scripts\test-integration.bat --build --tfs "Integration Tests" } + $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" + $AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json + $AppNameShort = $AppProductJson.nameShort + exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)"; .\scripts\test-integration.bat --build --tfs "Integration Tests" } displayName: Run integration tests condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index b31ce45550..6a787ad2b1 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -21,7 +21,6 @@ const nlsDev = require('vscode-nls-dev'); const root = path.dirname(__dirname); const commit = util.getVersion(root); const plumber = require('gulp-plumber'); -const _ = require('underscore'); const ext = require('./lib/extensions'); const extensionsPath = path.join(path.dirname(__dirname), 'extensions'); @@ -37,16 +36,16 @@ const tasks = compilations.map(function (tsconfigFile) { const absolutePath = path.join(extensionsPath, tsconfigFile); const relativeDirname = path.dirname(tsconfigFile); - const tsconfig = require(absolutePath); - const tsOptions = _.assign({}, tsconfig.extends ? require(path.join(extensionsPath, relativeDirname, tsconfig.extends)).compilerOptions : {}, tsconfig.compilerOptions); - tsOptions.verbose = false; - tsOptions.sourceMap = true; + const overrideOptions = {}; + overrideOptions.sourceMap = true; const name = relativeDirname.replace(/\//g, '-'); const root = path.join('extensions', relativeDirname); const srcBase = path.join(root, 'src'); const src = path.join(srcBase, '**'); + const srcOpts = { cwd: path.dirname(__dirname), base: srcBase }; + const out = path.join(root, 'out'); const baseUrl = getBaseUrl(out); @@ -63,12 +62,12 @@ const tasks = compilations.map(function (tsconfigFile) { function createPipeline(build, emitError) { const reporter = createReporter(); - tsOptions.inlineSources = !!build; - tsOptions.base = path.dirname(absolutePath); + overrideOptions.inlineSources = Boolean(build); + overrideOptions.base = path.dirname(absolutePath); - const compilation = tsb.create(tsOptions, null, null, err => reporter(err.toString())); + const compilation = tsb.create(absolutePath, overrideOptions, false, err => reporter(err.toString())); - return function () { + const pipeline = function () { const input = es.through(); const tsFilter = filter(['**/*.ts', '!**/lib/lib*.d.ts', '!**/node_modules/**'], { restore: true }); const output = input @@ -98,15 +97,19 @@ const tasks = compilations.map(function (tsconfigFile) { return es.duplex(input, output); }; - } - const srcOpts = { cwd: path.dirname(__dirname), base: srcBase }; + // add src-stream for project files + pipeline.tsProjectSrc = () => { + return compilation.src(srcOpts); + }; + return pipeline; + } const cleanTask = task.define(`clean-extension-${name}`, util.rimraf(out)); const compileTask = task.define(`compile-extension:${name}`, task.series(cleanTask, () => { const pipeline = createPipeline(false, true); - const input = gulp.src(src, srcOpts); + const input = pipeline.tsProjectSrc(); return input .pipe(pipeline()) @@ -115,8 +118,8 @@ const tasks = compilations.map(function (tsconfigFile) { const watchTask = task.define(`watch-extension:${name}`, task.series(cleanTask, () => { const pipeline = createPipeline(false); - const input = gulp.src(src, srcOpts); - const watchInput = watcher(src, srcOpts); + const input = pipeline.tsProjectSrc(); + const watchInput = watcher(src, { ...srcOpts, ...{ readDelay: 200 } }); return watchInput .pipe(util.incremental(pipeline, input)) @@ -125,7 +128,7 @@ const tasks = compilations.map(function (tsconfigFile) { const compileBuildTask = task.define(`compile-build-extension-${name}`, task.series(cleanTask, () => { const pipeline = createPipeline(true, true); - const input = gulp.src(src, srcOpts); + const input = pipeline.tsProjectSrc(); return input .pipe(pipeline()) @@ -156,8 +159,8 @@ const cleanExtensionsBuildTask = task.define('clean-extensions-build', util.rimr const compileExtensionsBuildTask = task.define('compile-extensions-build', task.series( cleanExtensionsBuildTask, task.define('bundle-extensions-build', () => ext.packageLocalExtensionsStream().pipe(gulp.dest('.build'))), - task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream().pipe(gulp.dest('.build'))), + task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream().pipe(gulp.dest('.build'))) )); gulp.task(compileExtensionsBuildTask); -exports.compileExtensionsBuildTask = compileExtensionsBuildTask; \ No newline at end of file +exports.compileExtensionsBuildTask = compileExtensionsBuildTask; diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index 338222a410..9da2f955be 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -17,6 +17,7 @@ const vfs = require('vinyl-fs'); const path = require('path'); const fs = require('fs'); const pall = require('p-all'); +const task = require('./lib/task'); /** * Hygiene works by creating cascading subsets of all our files and @@ -57,6 +58,7 @@ const indentationFilter = [ '!test/assert.js', // except specific folders + '!test/automation/out/**', '!test/smoke/out/**', '!extensions/vscode-api-tests/testWorkspace/**', '!extensions/vscode-api-tests/testWorkspace2/**', @@ -192,13 +194,13 @@ const tslintBaseFilter = [ ]; // {{SQL CARBON EDIT}} -const useStrictFilter = [ - 'src/**' -]; +// const useStrictFilter = [ +// 'src/**' +// ]; -const sqlFilter = [ - 'src/sql/**' -]; +// const sqlFilter = [ +// 'src/sql/**' +// ]; // {{SQL CARBON EDIT}} @@ -206,6 +208,7 @@ const tslintCoreFilter = [ 'src/**/*.ts', 'test/**/*.ts', '!extensions/**/*.ts', + '!test/automation/**', '!test/smoke/**', ...tslintBaseFilter ]; @@ -214,6 +217,7 @@ const tslintExtensionsFilter = [ 'extensions/**/*.ts', '!src/**/*.ts', '!test/**/*.ts', + 'test/automation/**/*.ts', ...tslintBaseFilter ]; @@ -256,6 +260,33 @@ gulp.task('tslint', () => { ]).pipe(es.through()); }); +function checkPackageJSON(actualPath) { + const actual = require(path.join(__dirname, '..', actualPath)); + const rootPackageJSON = require('../package.json'); + + for (let depName in actual.dependencies) { + const depVersion = actual.dependencies[depName]; + const rootDepVersion = rootPackageJSON.dependencies[depName]; + if (!rootDepVersion) { + // missing in root is allowed + continue; + } + if (depVersion !== rootDepVersion) { + this.emit('error', `The dependency ${depName} in '${actualPath}' (${depVersion}) is different than in the root package.json (${rootDepVersion})`); + } + } +} + +const checkPackageJSONTask = task.define('check-package-json', () => { + return gulp.src('package.json') + .pipe(es.through(function() { + checkPackageJSON.call(this, 'remote/package.json'); + checkPackageJSON.call(this, 'remote/web/package.json'); + })); +}); +gulp.task(checkPackageJSONTask); + + function hygiene(some) { let errorCount = 0; @@ -307,19 +338,19 @@ function hygiene(some) { // {{SQL CARBON EDIT}} // Check for unnecessary 'use strict' lines. These are automatically added by the alwaysStrict compiler option so don't need to be added manually - const useStrict = es.through(function (file) { - const lines = file.__lines; - // Only take the first 10 lines to reduce false positives- the compiler will throw an error if it's not the first non-comment line in a file - // (10 is used to account for copyright and extraneous newlines) - lines.slice(0, 10).forEach((line, i) => { - if (/\s*'use\s*strict\s*'/.test(line)) { - console.error(file.relative + '(' + (i + 1) + ',1): Unnecessary \'use strict\' - this is already added by the compiler'); - errorCount++; - } - }); + // const useStrict = es.through(function (file) { + // const lines = file.__lines; + // // Only take the first 10 lines to reduce false positives- the compiler will throw an error if it's not the first non-comment line in a file + // // (10 is used to account for copyright and extraneous newlines) + // lines.slice(0, 10).forEach((line, i) => { + // if (/\s*'use\s*strict\s*'/.test(line)) { + // console.error(file.relative + '(' + (i + 1) + ',1): Unnecessary \'use strict\' - this is already added by the compiler'); + // errorCount++; + // } + // }); - this.emit('data', file); - }); + // this.emit('data', file); + // }); // {{SQL CARBON EDIT}} END const formatting = es.map(function (file, cb) { @@ -370,16 +401,16 @@ function hygiene(some) { input = some; } - const tslintSqlConfiguration = tslint.Configuration.findConfiguration('tslint-sql.json', '.'); + // const tslintSqlConfiguration = tslint.Configuration.findConfiguration('tslint-sql.json', '.'); // TODO RESTORE const tslintSqlOptions = { fix: false, formatter: 'json' }; const sqlTsLinter = new tslint.Linter(tslintSqlOptions); - const sqlTsl = es.through(function (file) { - const contents = file.contents.toString('utf8'); - sqlTsLinter.lint(file.relative, contents, tslintSqlConfiguration.results); + // const sqlTsl = es.through(function (file) { //TODO restore + // const contents = file.contents.toString('utf8'); + // sqlTsLinter.lint(file.relative, contents, tslintSqlConfiguration.results); - this.emit('data', file); - }); + // this.emit('data', file); + // }); const productJsonFilter = filter('product.json', { restore: true }); @@ -393,15 +424,13 @@ function hygiene(some) { .pipe(filter(copyrightFilter)) .pipe(copyrights); - const typescript = result + let typescript = result .pipe(filter(tslintHygieneFilter)) - .pipe(formatting) - .pipe(tsl) - // {{SQL CARBON EDIT}} - .pipe(filter(useStrictFilter)) - .pipe(useStrict) - .pipe(filter(sqlFilter)) - .pipe(sqlTsl); + .pipe(formatting); + + if (!process.argv.some(arg => arg === '--skip-tslint')) { + typescript = typescript.pipe(tsl); + } const javascript = result .pipe(filter(eslintFilter)) @@ -487,7 +516,7 @@ function createGitIndexVinyls(paths) { .then(r => r.filter(p => !!p)); } -gulp.task('hygiene', () => hygiene()); +gulp.task('hygiene', task.series(checkPackageJSONTask, () => hygiene())); // this allows us to run hygiene as a git pre-commit hook if (require.main === module) { diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index ee01094995..eaeaad94e9 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -60,8 +60,7 @@ const nodeModules = [ const vscodeEntryPoints = _.flatten([ buildfile.entrypoint('vs/workbench/workbench.desktop.main'), buildfile.base, - buildfile.serviceWorker, - buildfile.workbench, + buildfile.workbenchDesktop, buildfile.code ]); @@ -125,6 +124,7 @@ const optimizeVSCodeTask = task.define('optimize-vscode', task.series( resources: vscodeResources, loaderConfig: common.loaderConfig(nodeModules), out: 'out-vscode', + inlineAmdImages: true, bundleInfo: undefined }) )); @@ -468,7 +468,7 @@ gulp.task(task.define( optimizeVSCodeTask, function () { const pathToMetadata = './out-vscode/nls.metadata.json'; - const pathToExtensions = './extensions/*'; + const pathToExtensions = '.build/extensions/*'; const pathToSetup = 'build/win32/**/{Default.isl,messages.en.isl}'; return es.merge( @@ -489,7 +489,7 @@ gulp.task(task.define( optimizeVSCodeTask, function () { const pathToMetadata = './out-vscode/nls.metadata.json'; - const pathToExtensions = './extensions/*'; + const pathToExtensions = '.build/extensions/*'; const pathToSetup = 'build/win32/**/{Default.isl,messages.en.isl}'; return es.merge( diff --git a/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js index 752f9a19ff..271f39a5a7 100644 --- a/build/gulpfile.vscode.linux.js +++ b/build/gulpfile.vscode.linux.js @@ -43,6 +43,7 @@ function prepareDebPackage(arch) { .pipe(replace('@@NAME_LONG@@', product.nameLong)) .pipe(replace('@@NAME_SHORT@@', product.nameShort)) .pipe(replace('@@NAME@@', product.applicationName)) + .pipe(replace('@@EXEC@@', `/usr/share/${product.applicationName}/${product.applicationName}`)) .pipe(replace('@@ICON@@', product.linuxIconName)) .pipe(replace('@@URLPROTOCOL@@', product.urlProtocol)); @@ -136,6 +137,7 @@ function prepareRpmPackage(arch) { .pipe(replace('@@NAME_LONG@@', product.nameLong)) .pipe(replace('@@NAME_SHORT@@', product.nameShort)) .pipe(replace('@@NAME@@', product.applicationName)) + .pipe(replace('@@EXEC@@', `/usr/share/${product.applicationName}/${product.applicationName}`)) .pipe(replace('@@ICON@@', product.linuxIconName)) .pipe(replace('@@URLPROTOCOL@@', product.urlProtocol)); @@ -206,21 +208,25 @@ function prepareSnapPackage(arch) { const destination = getSnapBuildPath(arch); return function () { + // A desktop file that is placed in snap/gui will be placed into meta/gui verbatim. const desktop = gulp.src('resources/linux/code.desktop', { base: '.' }) - .pipe(rename(`usr/share/applications/${product.applicationName}.desktop`)); + .pipe(rename(`snap/gui/${product.applicationName}.desktop`)); + // A desktop file that is placed in snap/gui will be placed into meta/gui verbatim. const desktopUrlHandler = gulp.src('resources/linux/code-url-handler.desktop', { base: '.' }) - .pipe(rename(`usr/share/applications/${product.applicationName}-url-handler.desktop`)); + .pipe(rename(`snap/gui/${product.applicationName}-url-handler.desktop`)); const desktops = es.merge(desktop, desktopUrlHandler) .pipe(replace('@@NAME_LONG@@', product.nameLong)) .pipe(replace('@@NAME_SHORT@@', product.nameShort)) .pipe(replace('@@NAME@@', product.applicationName)) - .pipe(replace('@@ICON@@', `/usr/share/pixmaps/${product.linuxIconName}.png`)) + .pipe(replace('@@EXEC@@', `${product.applicationName} --force-user-env`)) + .pipe(replace('@@ICON@@', `\${SNAP}/meta/gui/${product.linuxIconName}.png`)) .pipe(replace('@@URLPROTOCOL@@', product.urlProtocol)); + // An icon that is placed in snap/gui will be placed into meta/gui verbatim. const icon = gulp.src('resources/linux/code.png', { base: '.' }) - .pipe(rename(`usr/share/pixmaps/${product.linuxIconName}.png`)); + .pipe(rename(`snap/gui/${product.linuxIconName}.png`)); const code = gulp.src(binaryDir + '/**/*', { base: binaryDir }) .pipe(rename(function (p) { p.dirname = `usr/share/${product.applicationName}/${p.dirname}`; })); @@ -241,7 +247,8 @@ function prepareSnapPackage(arch) { function buildSnapPackage(arch) { const snapBuildPath = getSnapBuildPath(arch); - return shell.task(`cd ${snapBuildPath} && snapcraft build`); + // Default target for snapcraft runs: pull, build, stage and prime, and finally assembles the snap. + return shell.task(`cd ${snapBuildPath} && snapcraft`); } const BUILD_TARGETS = [ diff --git a/build/gulpfile.vscode.web.js b/build/gulpfile.vscode.web.js index 7978d3520e..e654979844 100644 --- a/build/gulpfile.vscode.web.js +++ b/build/gulpfile.vscode.web.js @@ -6,150 +6,11 @@ 'use strict'; const gulp = require('gulp'); -const path = require('path'); -const es = require('event-stream'); -const util = require('./lib/util'); -const task = require('./lib/task'); -const common = require('./lib/optimize'); -const product = require('../product.json'); -const rename = require('gulp-rename'); -const filter = require('gulp-filter'); -const json = require('gulp-json-editor'); -const _ = require('underscore'); -const deps = require('./dependencies'); -const vfs = require('vinyl-fs'); -const packageJson = require('../package.json'); -const { compileBuildTask } = require('./gulpfile.compile'); -const REPO_ROOT = path.dirname(__dirname); -const commit = util.getVersion(REPO_ROOT); -const BUILD_ROOT = path.dirname(REPO_ROOT); -const WEB_FOLDER = path.join(REPO_ROOT, 'remote', 'web'); +const noop = () => { return Promise.resolve(); }; -const productionDependencies = deps.getProductionDependencies(WEB_FOLDER); - -const nodeModules = Object.keys(product.dependencies || {}) - .concat(_.uniq(productionDependencies.map(d => d.name))); - -const vscodeWebResources = [ - - // Workbench - 'out-build/vs/{base,platform,editor,workbench}/**/*.{svg,png,html}', - 'out-build/vs/base/browser/ui/octiconLabel/octicons/**', - 'out-build/vs/**/markdown.css', - - // Webview - 'out-build/vs/workbench/contrib/webview/browser/pre/*.js', - - // Extension Worker - 'out-build/vs/workbench/services/extensions/worker/extensionHostWorkerMain.js', - - // Excludes - '!out-build/vs/**/{node,electron-browser,electron-main}/**', - '!out-build/vs/editor/standalone/**', - '!out-build/vs/workbench/**/*-tb.png', - '!**/test/**' -]; - -const buildfile = require('../src/buildfile'); - -const vscodeWebEntryPoints = [ - buildfile.workbenchWeb, - buildfile.serviceWorker, - buildfile.workerExtensionHost, - buildfile.keyboardMaps, - buildfile.base -]; - -const optimizeVSCodeWebTask = task.define('optimize-vscode-web', task.series( - util.rimraf('out-vscode-web'), - common.optimizeTask({ - src: 'out-build', - entryPoints: _.flatten(vscodeWebEntryPoints), - otherSources: [], - resources: vscodeWebResources, - loaderConfig: common.loaderConfig(nodeModules), - out: 'out-vscode-web', - bundleInfo: undefined - }) -)); - -const minifyVSCodeWebTask = task.define('minify-vscode-web', task.series( - optimizeVSCodeWebTask, - util.rimraf('out-vscode-web-min'), - common.minifyTask('out-vscode-web', `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`) -)); -gulp.task(minifyVSCodeWebTask); - -function packageTask(sourceFolderName, destinationFolderName) { - const destination = path.join(BUILD_ROOT, destinationFolderName); - - return () => { - const src = gulp.src(sourceFolderName + '/**', { base: '.' }) - .pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + sourceFolderName), 'out'); })) - .pipe(filter(['**', '!**/*.js.map'])); - - const sources = es.merge(src); - - let version = packageJson.version; - const quality = product.quality; - - if (quality && quality !== 'stable') { - version += '-' + quality; - } - - const name = product.nameShort; - const packageJsonStream = gulp.src(['remote/web/package.json'], { base: 'remote/web' }) - .pipe(json({ name, version })); - - const date = new Date().toISOString(); - - const productJsonStream = gulp.src(['product.json'], { base: '.' }) - .pipe(json({ commit, date })); - - const license = gulp.src(['remote/LICENSE'], { base: 'remote' }); - - const dependenciesSrc = _.flatten(productionDependencies.map(d => path.relative(REPO_ROOT, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`, `!${d}/.bin/**`])); - - const deps = gulp.src(dependenciesSrc, { base: 'remote/web', dot: true }) - .pipe(filter(['**', '!**/package-lock.json'])) - .pipe(util.cleanNodeModules(path.join(__dirname, '.nativeignore'))); - - const favicon = gulp.src('resources/server/favicon.ico', { base: 'resources/server' }); - - let all = es.merge( - packageJsonStream, - productJsonStream, - license, - sources, - deps, - favicon - ); - - let result = all - .pipe(util.skipDirectories()) - .pipe(util.fixWin32DirectoryPermissions()); - - return result.pipe(vfs.dest(destination)); - }; -} - -const dashed = (str) => (str ? `-${str}` : ``); - -['', 'min'].forEach(minified => { - const sourceFolderName = `out-vscode-web${dashed(minified)}`; - const destinationFolderName = `vscode-web`; - - const vscodeWebTaskCI = task.define(`vscode-web${dashed(minified)}-ci`, task.series( - minified ? minifyVSCodeWebTask : optimizeVSCodeWebTask, - util.rimraf(path.join(BUILD_ROOT, destinationFolderName)), - packageTask(sourceFolderName, destinationFolderName) - )); - gulp.task(vscodeWebTaskCI); - - const vscodeWebTask = task.define(`vscode-web${dashed(minified)}`, task.series( - compileBuildTask, - vscodeWebTaskCI - )); - gulp.task(vscodeWebTask); -}); +gulp.task('minify-vscode-web', noop); +gulp.task('vscode-web', noop); +gulp.task('vscode-web-min', noop); +gulp.task('vscode-web-ci', noop); +gulp.task('vscode-web-min-ci', noop); diff --git a/build/lib/compilation.js b/build/lib/compilation.js index d0230384fb..6b65b88e2d 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -11,7 +11,6 @@ const bom = require("gulp-bom"); const sourcemaps = require("gulp-sourcemaps"); const tsb = require("gulp-tsb"); const path = require("path"); -const _ = require("underscore"); const monacodts = require("../monaco/api"); const nls = require("./nls"); const reporter_1 = require("./reporter"); @@ -22,14 +21,7 @@ const watch = require('./watch'); const reporter = reporter_1.createReporter(); function getTypeScriptCompilerOptions(src) { const rootDir = path.join(__dirname, `../../${src}`); - const tsconfig = require(`../../${src}/tsconfig.json`); - let options; - if (tsconfig.extends) { - options = Object.assign({}, require(path.join(rootDir, tsconfig.extends)).compilerOptions, tsconfig.compilerOptions); - } - else { - options = tsconfig.compilerOptions; - } + let options = {}; options.verbose = false; options.sourceMap = true; if (process.env['VSCODE_NO_SOURCEMAP']) { // To be used by developers in a hurry @@ -38,15 +30,14 @@ function getTypeScriptCompilerOptions(src) { options.rootDir = rootDir; options.baseUrl = rootDir; options.sourceRoot = util.toFileUri(rootDir); - options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 'CRLF' : 'LF'; + options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 0 : 1; return options; } function createCompile(src, build, emitError) { - const opts = _.clone(getTypeScriptCompilerOptions(src)); - opts.inlineSources = !!build; - opts.noFilesystemLookup = true; - const ts = tsb.create(opts, true, undefined, err => reporter(err.toString())); - return function (token) { + const projectPath = path.join(__dirname, '../../', src, 'tsconfig.json'); + const overrideOptions = Object.assign(Object.assign({}, getTypeScriptCompilerOptions(src)), { inlineSources: Boolean(build) }); + const compilation = tsb.create(projectPath, overrideOptions, false, err => reporter(err)); + function pipeline(token) { const utf8Filter = util.filter(data => /(\/|\\)test(\/|\\).*utf8/.test(data.path)); const tsFilter = util.filter(data => /\.ts$/.test(data.path)); const noDeclarationsFilter = util.filter(data => !(/\.d\.ts$/.test(data.path))); @@ -57,30 +48,28 @@ function createCompile(src, build, emitError) { .pipe(utf8Filter.restore) .pipe(tsFilter) .pipe(util.loadSourcemaps()) - .pipe(ts(token)) + .pipe(compilation(token)) .pipe(noDeclarationsFilter) .pipe(build ? nls() : es.through()) .pipe(noDeclarationsFilter.restore) .pipe(sourcemaps.write('.', { addComment: false, includeContent: !!build, - sourceRoot: opts.sourceRoot + sourceRoot: overrideOptions.sourceRoot })) .pipe(tsFilter.restore) .pipe(reporter.end(!!emitError)); return es.duplex(input, output); + } + pipeline.tsProjectSrc = () => { + return compilation.src({ base: src }); }; + return pipeline; } -const typesDts = [ - 'node_modules/typescript/lib/*.d.ts', - 'node_modules/@types/**/*.d.ts', - '!node_modules/@types/webpack/**/*', - '!node_modules/@types/uglify-js/**/*', -]; function compileTask(src, out, build) { return function () { const compile = createCompile(src, build, true); - const srcPipe = es.merge(gulp.src(`${src}/**`, { base: `${src}` }), gulp.src(typesDts)); + const srcPipe = gulp.src(`${src}/**`, { base: `${src}` }); let generator = new MonacoGenerator(false); if (src === 'src') { generator.execute(); @@ -95,8 +84,8 @@ exports.compileTask = compileTask; function watchTask(out, build) { return function () { const compile = createCompile('src', build); - const src = es.merge(gulp.src('src/**', { base: 'src' }), gulp.src(typesDts)); - const watchSrc = watch('src/**', { base: 'src' }); + const src = gulp.src('src/**', { base: 'src' }); + const watchSrc = watch('src/**', { base: 'src', readDelay: 200 }); let generator = new MonacoGenerator(true); generator.execute(); return watchSrc diff --git a/build/lib/compilation.ts b/build/lib/compilation.ts index cfc145f5c7..4f5a7b8e80 100644 --- a/build/lib/compilation.ts +++ b/build/lib/compilation.ts @@ -12,27 +12,21 @@ import * as bom from 'gulp-bom'; import * as sourcemaps from 'gulp-sourcemaps'; import * as tsb from 'gulp-tsb'; import * as path from 'path'; -import * as _ from 'underscore'; import * as monacodts from '../monaco/api'; import * as nls from './nls'; import { createReporter } from './reporter'; import * as util from './util'; import * as fancyLog from 'fancy-log'; import * as ansiColors from 'ansi-colors'; +import ts = require('typescript'); const watch = require('./watch'); const reporter = createReporter(); -function getTypeScriptCompilerOptions(src: string) { +function getTypeScriptCompilerOptions(src: string): ts.CompilerOptions { const rootDir = path.join(__dirname, `../../${src}`); - const tsconfig = require(`../../${src}/tsconfig.json`); - let options: { [key: string]: any }; - if (tsconfig.extends) { - options = Object.assign({}, require(path.join(rootDir, tsconfig.extends)).compilerOptions, tsconfig.compilerOptions); - } else { - options = tsconfig.compilerOptions; - } + let options: ts.CompilerOptions = {}; options.verbose = false; options.sourceMap = true; if (process.env['VSCODE_NO_SOURCEMAP']) { // To be used by developers in a hurry @@ -41,18 +35,17 @@ function getTypeScriptCompilerOptions(src: string) { options.rootDir = rootDir; options.baseUrl = rootDir; options.sourceRoot = util.toFileUri(rootDir); - options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 'CRLF' : 'LF'; + options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 0 : 1; return options; } -function createCompile(src: string, build: boolean, emitError?: boolean): (token?: util.ICancellationToken) => NodeJS.ReadWriteStream { - const opts = _.clone(getTypeScriptCompilerOptions(src)); - opts.inlineSources = !!build; - opts.noFilesystemLookup = true; +function createCompile(src: string, build: boolean, emitError?: boolean) { + const projectPath = path.join(__dirname, '../../', src, 'tsconfig.json'); + const overrideOptions = { ...getTypeScriptCompilerOptions(src), inlineSources: Boolean(build) }; - const ts = tsb.create(opts, true, undefined, err => reporter(err.toString())); + const compilation = tsb.create(projectPath, overrideOptions, false, err => reporter(err)); - return function (token?: util.ICancellationToken) { + function pipeline(token?: util.ICancellationToken) { const utf8Filter = util.filter(data => /(\/|\\)test(\/|\\).*utf8/.test(data.path)); const tsFilter = util.filter(data => /\.ts$/.test(data.path)); @@ -65,39 +58,31 @@ function createCompile(src: string, build: boolean, emitError?: boolean): (token .pipe(utf8Filter.restore) .pipe(tsFilter) .pipe(util.loadSourcemaps()) - .pipe(ts(token)) + .pipe(compilation(token)) .pipe(noDeclarationsFilter) .pipe(build ? nls() : es.through()) .pipe(noDeclarationsFilter.restore) .pipe(sourcemaps.write('.', { addComment: false, includeContent: !!build, - sourceRoot: opts.sourceRoot + sourceRoot: overrideOptions.sourceRoot })) .pipe(tsFilter.restore) .pipe(reporter.end(!!emitError)); return es.duplex(input, output); + } + pipeline.tsProjectSrc = () => { + return compilation.src({ base: src }); }; + return pipeline; } -const typesDts = [ - 'node_modules/typescript/lib/*.d.ts', - 'node_modules/@types/**/*.d.ts', - '!node_modules/@types/webpack/**/*', - '!node_modules/@types/uglify-js/**/*', -]; - export function compileTask(src: string, out: string, build: boolean): () => NodeJS.ReadWriteStream { return function () { const compile = createCompile(src, build, true); - - const srcPipe = es.merge( - gulp.src(`${src}/**`, { base: `${src}` }), - gulp.src(typesDts), - ); - + const srcPipe = gulp.src(`${src}/**`, { base: `${src}` }); let generator = new MonacoGenerator(false); if (src === 'src') { generator.execute(); @@ -115,11 +100,8 @@ export function watchTask(out: string, build: boolean): () => NodeJS.ReadWriteSt return function () { const compile = createCompile('src', build); - const src = es.merge( - gulp.src('src/**', { base: 'src' }), - gulp.src(typesDts), - ); - const watchSrc = watch('src/**', { base: 'src' }); + const src = gulp.src('src/**', { base: 'src' }); + const watchSrc = watch('src/**', { base: 'src', readDelay: 200 }); let generator = new MonacoGenerator(true); generator.execute(); diff --git a/build/lib/extensions.js b/build/lib/extensions.js index 4f406850d9..339a4a5780 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -101,7 +101,7 @@ function fromLocalWebpack(extensionPath) { result.emit('error', compilation.warnings.join('\n')); } }; - const webpackConfig = Object.assign({}, require(webpackConfigPath), { mode: 'production' }); + const webpackConfig = Object.assign(Object.assign({}, require(webpackConfigPath)), { mode: 'production' }); const relativeOutputPath = path.relative(extensionPath, webpackConfig.output.path); return webpackGulp(webpackConfig, webpack, webpackDone) .pipe(es.through(function (data) { diff --git a/build/lib/i18n.js b/build/lib/i18n.js index 50d2eeb082..d65b4a7ce4 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -176,6 +176,7 @@ class XLF { this.buffer.push(line.toString()); } } +exports.XLF = XLF; XLF.parsePseudo = function (xlfString) { return new Promise((resolve) => { let parser = new xml2js.Parser(); @@ -248,7 +249,6 @@ XLF.parse = function (xlfString) { }); }); }; -exports.XLF = XLF; class Limiter { constructor(maxDegreeOfParalellism) { this.maxDegreeOfParalellism = maxDegreeOfParalellism; @@ -586,7 +586,7 @@ function createXlfFilesForExtensions() { } return _xlf; } - gulp.src([`./extensions/${extensionName}/package.nls.json`, `./extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(event_stream_1.through(function (file) { + gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(event_stream_1.through(function (file) { if (file.isBuffer()) { const buffer = file.contents; const basename = path.basename(file.path); @@ -609,7 +609,7 @@ function createXlfFilesForExtensions() { } else if (basename === 'nls.metadata.json') { const json = JSON.parse(buffer.toString('utf8')); - const relPath = path.relative(`./extensions/${extensionName}`, path.dirname(file.path)); + const relPath = path.relative(`.build/extensions/${extensionName}`, path.dirname(file.path)); for (let file in json) { const fileContent = json[file]; getXlf().addFile(`extensions/${extensionName}/${relPath}/${file}`, fileContent.keys, fileContent.messages); @@ -912,8 +912,8 @@ function pullCoreAndExtensionsXlfFiles(apiHostname, username, password, language _coreAndExtensionResources.push(...json.workbench); // extensions let extensionsToLocalize = Object.create(null); - glob.sync('./extensions/**/*.nls.json').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); - glob.sync('./extensions/*/node_modules/vscode-nls').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); + glob.sync('.build/extensions/**/*.nls.json').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); + glob.sync('.build/extensions/*/node_modules/vscode-nls').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); Object.keys(extensionsToLocalize).forEach(extension => { _coreAndExtensionResources.push({ name: extension, project: extensionsProject }); }); @@ -1086,7 +1086,7 @@ function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pse resultingTranslationPaths.push({ id: 'vscode', resourceName: 'main.i18n.json' }); this.queue(translatedMainFile); for (let extension in extensionsPacks) { - const translatedExtFile = createI18nFile(`./extensions/${extension}`, extensionsPacks[extension]); + const translatedExtFile = createI18nFile(`.build/extensions/${extension}`, extensionsPacks[extension]); this.queue(translatedExtFile); const externalExtensionId = externalExtensions[extension]; if (externalExtensionId) { diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 570d97669c..da50b1eb2d 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -170,6 +170,10 @@ "name": "vs/workbench/contrib/webview", "project": "vscode-workbench" }, + { + "name": "vs/workbench/contrib/customEditor", + "project": "vscode-workbench" + }, { "name": "vs/workbench/contrib/welcome", "project": "vscode-workbench" diff --git a/build/lib/i18n.ts b/build/lib/i18n.ts index 616a672ce4..c3d7228f42 100644 --- a/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -709,7 +709,7 @@ export function createXlfFilesForExtensions(): ThroughStream { } return _xlf; } - gulp.src([`./extensions/${extensionName}/package.nls.json`, `./extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(through(function (file: File) { + gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(through(function (file: File) { if (file.isBuffer()) { const buffer: Buffer = file.contents as Buffer; const basename = path.basename(file.path); @@ -729,7 +729,7 @@ export function createXlfFilesForExtensions(): ThroughStream { getXlf().addFile(`extensions/${extensionName}/package`, keys, messages); } else if (basename === 'nls.metadata.json') { const json: BundledExtensionFormat = JSON.parse(buffer.toString('utf8')); - const relPath = path.relative(`./extensions/${extensionName}`, path.dirname(file.path)); + const relPath = path.relative(`.build/extensions/${extensionName}`, path.dirname(file.path)); for (let file in json) { const fileContent = json[file]; getXlf().addFile(`extensions/${extensionName}/${relPath}/${file}`, fileContent.keys, fileContent.messages); @@ -1053,8 +1053,8 @@ export function pullCoreAndExtensionsXlfFiles(apiHostname: string, username: str // extensions let extensionsToLocalize = Object.create(null); - glob.sync('./extensions/**/*.nls.json').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); - glob.sync('./extensions/*/node_modules/vscode-nls').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); + glob.sync('.build/extensions/**/*.nls.json').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); + glob.sync('.build/extensions/*/node_modules/vscode-nls').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); Object.keys(extensionsToLocalize).forEach(extension => { _coreAndExtensionResources.push({ name: extension, project: extensionsProject }); @@ -1253,7 +1253,7 @@ export function prepareI18nPackFiles(externalExtensions: Map, resultingT this.queue(translatedMainFile); for (let extension in extensionsPacks) { - const translatedExtFile = createI18nFile(`./extensions/${extension}`, extensionsPacks[extension]); + const translatedExtFile = createI18nFile(`.build/extensions/${extension}`, extensionsPacks[extension]); this.queue(translatedExtFile); const externalExtensionId = externalExtensions[extension]; diff --git a/build/lib/optimize.js b/build/lib/optimize.js index 3de6f74abf..6acb1597fb 100644 --- a/build/lib/optimize.js +++ b/build/lib/optimize.js @@ -5,6 +5,7 @@ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); const es = require("event-stream"); +const fs = require("fs"); const gulp = require("gulp"); const concat = require("gulp-concat"); const minifyCSS = require("gulp-cssnano"); @@ -17,7 +18,7 @@ const fancyLog = require("fancy-log"); const ansiColors = require("ansi-colors"); const path = require("path"); const pump = require("pump"); -const uglifyes = require("uglify-es"); +const terser = require("terser"); const VinylFile = require("vinyl"); const bundle = require("./bundle"); const i18n_1 = require("./i18n"); @@ -134,6 +135,14 @@ function optimizeTask(opts) { if (err || !result) { return bundlesStream.emit('error', JSON.stringify(err)); } + if (opts.inlineAmdImages) { + try { + result = inlineAmdImages(src, result); + } + catch (err) { + return bundlesStream.emit('error', JSON.stringify(err)); + } + } toBundleStream(src, bundledFileHeader, result.files).pipe(bundlesStream); // Remove css inlined resources const filteredResources = resources.slice(); @@ -169,6 +178,39 @@ function optimizeTask(opts) { }; } exports.optimizeTask = optimizeTask; +function inlineAmdImages(src, result) { + for (const outputFile of result.files) { + for (const sourceFile of outputFile.sources) { + if (sourceFile.path && /\.js$/.test(sourceFile.path)) { + sourceFile.contents = sourceFile.contents.replace(/\([^.]+\.registerAndGetAmdImageURL\(([^)]+)\)\)/g, (_, m0) => { + let imagePath = m0; + // remove `` or '' + if ((imagePath.charAt(0) === '`' && imagePath.charAt(imagePath.length - 1) === '`') + || (imagePath.charAt(0) === '\'' && imagePath.charAt(imagePath.length - 1) === '\'')) { + imagePath = imagePath.substr(1, imagePath.length - 2); + } + if (!/\.(png|svg)$/.test(imagePath)) { + console.log(`original: ${_}`); + return _; + } + const repoLocation = path.join(src, imagePath); + const absoluteLocation = path.join(REPO_ROOT_PATH, repoLocation); + if (!fs.existsSync(absoluteLocation)) { + const message = `Invalid amd image url in file ${sourceFile.path}: ${imagePath}`; + console.log(message); + throw new Error(message); + } + const fileContents = fs.readFileSync(absoluteLocation); + const mime = /\.svg$/.test(imagePath) ? 'image/svg+xml' : 'image/png'; + // Mark the file as inlined so we don't ship it by itself + result.cssInlinedResources.push(repoLocation); + return `("data:${mime};base64,${fileContents.toString('base64')}")`; + }); + } + } + } + return result; +} /** * Wrap around uglify and allow the preserveComments function * to have a file "context" to include our copyright only once per file. @@ -199,7 +241,7 @@ function uglifyWithCopyrights() { return false; }; }; - const minify = composer(uglifyes); + const minify = composer(terser); const input = es.through(); const output = input .pipe(flatmap((stream, f) => { diff --git a/build/lib/optimize.ts b/build/lib/optimize.ts index 54a7439985..1f8af4c62a 100644 --- a/build/lib/optimize.ts +++ b/build/lib/optimize.ts @@ -6,6 +6,7 @@ 'use strict'; import * as es from 'event-stream'; +import * as fs from 'fs'; import * as gulp from 'gulp'; import * as concat from 'gulp-concat'; import * as minifyCSS from 'gulp-cssnano'; @@ -19,7 +20,7 @@ import * as ansiColors from 'ansi-colors'; import * as path from 'path'; import * as pump from 'pump'; import * as sm from 'source-map'; -import * as uglifyes from 'uglify-es'; +import * as terser from 'terser'; import * as VinylFile from 'vinyl'; import * as bundle from './bundle'; import { Language, processNlsFiles } from './i18n'; @@ -161,6 +162,10 @@ export interface IOptimizeTaskOpts { * (emit bundleInfo.json file) */ bundleInfo: boolean; + /** + * replace calls to `registerAndGetAmdImageURL` with data uris + */ + inlineAmdImages: boolean; /** * (out folder name) */ @@ -194,6 +199,14 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr bundle.bundle(entryPoints, loaderConfig, function (err, result) { if (err || !result) { return bundlesStream.emit('error', JSON.stringify(err)); } + if (opts.inlineAmdImages) { + try { + result = inlineAmdImages(src, result); + } catch (err) { + return bundlesStream.emit('error', JSON.stringify(err)); + } + } + toBundleStream(src, bundledFileHeader, result.files).pipe(bundlesStream); // Remove css inlined resources @@ -238,6 +251,42 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr }; } +function inlineAmdImages(src: string, result: bundle.IBundleResult): bundle.IBundleResult { + for (const outputFile of result.files) { + for (const sourceFile of outputFile.sources) { + if (sourceFile.path && /\.js$/.test(sourceFile.path)) { + sourceFile.contents = sourceFile.contents.replace(/\([^.]+\.registerAndGetAmdImageURL\(([^)]+)\)\)/g, (_, m0) => { + let imagePath = m0; + // remove `` or '' + if ((imagePath.charAt(0) === '`' && imagePath.charAt(imagePath.length - 1) === '`') + || (imagePath.charAt(0) === '\'' && imagePath.charAt(imagePath.length - 1) === '\'')) { + imagePath = imagePath.substr(1, imagePath.length - 2); + } + if (!/\.(png|svg)$/.test(imagePath)) { + console.log(`original: ${_}`); + return _; + } + const repoLocation = path.join(src, imagePath); + const absoluteLocation = path.join(REPO_ROOT_PATH, repoLocation); + if (!fs.existsSync(absoluteLocation)) { + const message = `Invalid amd image url in file ${sourceFile.path}: ${imagePath}`; + console.log(message); + throw new Error(message); + } + const fileContents = fs.readFileSync(absoluteLocation); + const mime = /\.svg$/.test(imagePath) ? 'image/svg+xml' : 'image/png'; + + // Mark the file as inlined so we don't ship it by itself + result.cssInlinedResources.push(repoLocation); + + return `("data:${mime};base64,${fileContents.toString('base64')}")`; + }); + } + } + } + return result; +} + declare class FileWithCopyright extends VinylFile { public __hasOurCopyright: boolean; } @@ -275,7 +324,7 @@ function uglifyWithCopyrights(): NodeJS.ReadWriteStream { }; }; - const minify = (composer as any)(uglifyes); + const minify = (composer as any)(terser); const input = es.through(); const output = input .pipe(flatmap((stream, f) => { diff --git a/build/lib/tslint/noUnexternalizedStringsRule.js b/build/lib/tslint/noUnexternalizedStringsRule.js index 9ae2da6121..0c01f5edcb 100644 --- a/build/lib/tslint/noUnexternalizedStringsRule.js +++ b/build/lib/tslint/noUnexternalizedStringsRule.js @@ -11,6 +11,9 @@ const Lint = require("tslint"); */ class Rule extends Lint.Rules.AbstractRule { apply(sourceFile) { + if (/\.d.ts$/.test(sourceFile.fileName)) { + return []; + } return this.applyWithWalker(new NoUnexternalizedStringsRuleWalker(sourceFile, this.getOptions())); } } diff --git a/build/lib/tslint/noUnexternalizedStringsRule.ts b/build/lib/tslint/noUnexternalizedStringsRule.ts index 1a2108f553..0b8c2e4bf0 100644 --- a/build/lib/tslint/noUnexternalizedStringsRule.ts +++ b/build/lib/tslint/noUnexternalizedStringsRule.ts @@ -11,6 +11,9 @@ import * as Lint from 'tslint'; */ export class Rule extends Lint.Rules.AbstractRule { public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + if (/\.d.ts$/.test(sourceFile.fileName)) { + return []; + } return this.applyWithWalker(new NoUnexternalizedStringsRuleWalker(sourceFile, this.getOptions())); } } diff --git a/build/lib/typings/gulp-tsb.d.ts b/build/lib/typings/gulp-tsb.d.ts index 600bfacf26..df9bb34d3f 100644 --- a/build/lib/typings/gulp-tsb.d.ts +++ b/build/lib/typings/gulp-tsb.d.ts @@ -7,10 +7,12 @@ declare module "gulp-tsb" { } export interface IncrementalCompiler { - (token?:ICancellationToken): NodeJS.ReadWriteStream; - // program?: ts.Program; + (token?: ICancellationToken): NodeJS.ReadWriteStream; + src(opts?: { + cwd?: string; + base?: string; + }): NodeJS.ReadStream; } + export function create(projectPath: string, existingOptions: any, verbose?: boolean, onError?: (message: any) => void): IncrementalCompiler; - export function create(configOrName: { [option: string]: string | number | boolean; } | string, verbose?: boolean, json?: boolean, onError?: (message: any) => void): IncrementalCompiler; - -} \ No newline at end of file +} diff --git a/build/lib/util.js b/build/lib/util.js index 7d38cb229d..04fd9f3ec4 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -121,7 +121,7 @@ function loadSourcemaps() { return; } if (!f.contents) { - cb(new Error('empty file')); + cb(undefined, f); return; } const contents = f.contents.toString('utf8'); diff --git a/build/lib/util.ts b/build/lib/util.ts index f31d8c0cbc..974c20ef07 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -165,7 +165,7 @@ export function loadSourcemaps(): NodeJS.ReadWriteStream { } if (!f.contents) { - cb(new Error('empty file')); + cb(undefined, f); return; } diff --git a/build/lib/watch/index.js b/build/lib/watch/index.js index 1f5b3c60ee..beb7abbe42 100644 --- a/build/lib/watch/index.js +++ b/build/lib/watch/index.js @@ -5,17 +5,6 @@ const es = require('event-stream'); -/** Ugly hack for gulp-tsb */ -function handleDeletions() { - return es.mapSync(f => { - if (/\.ts$/.test(f.relative) && !f.contents) { - f.contents = Buffer.from(''); - f.stat = { mtime: new Date() }; - } - - return f; - }); -} let watch = undefined; @@ -24,6 +13,5 @@ if (!watch) { } module.exports = function () { - return watch.apply(null, arguments) - .pipe(handleDeletions()); + return watch.apply(null, arguments); }; diff --git a/build/monaco/api.js b/build/monaco/api.js index 4903425434..a81b4db3e5 100644 --- a/build/monaco/api.js +++ b/build/monaco/api.js @@ -148,8 +148,9 @@ function getMassagedTopLevelDeclarationText(sourceFile, declaration, importName, } }); } - result = result.replace(/export default/g, 'export'); - result = result.replace(/export declare/g, 'export'); + result = result.replace(/export default /g, 'export '); + result = result.replace(/export declare /g, 'export '); + result = result.replace(/declare /g, ''); if (declaration.kind === ts.SyntaxKind.EnumDeclaration) { result = result.replace(/const enum/, 'enum'); enums.push(result); diff --git a/build/monaco/api.ts b/build/monaco/api.ts index 211adb701c..221cd06975 100644 --- a/build/monaco/api.ts +++ b/build/monaco/api.ts @@ -178,8 +178,9 @@ function getMassagedTopLevelDeclarationText(sourceFile: ts.SourceFile, declarati } }); } - result = result.replace(/export default/g, 'export'); - result = result.replace(/export declare/g, 'export'); + result = result.replace(/export default /g, 'export '); + result = result.replace(/export declare /g, 'export '); + result = result.replace(/declare /g, ''); if (declaration.kind === ts.SyntaxKind.EnumDeclaration) { result = result.replace(/const enum/, 'enum'); diff --git a/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe index a4cf5a9cf0..ad41a725df 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -62,6 +62,7 @@ export interface ICommandHandler { #includeAll(vs/editor/common/editorCommon;editorOptions.=>): IScrollEvent #includeAll(vs/editor/common/model/textModelEvents): #includeAll(vs/editor/common/controller/cursorEvents): +#include(vs/platform/accessibility/common/accessibility): AccessibilitySupport #includeAll(vs/editor/common/config/editorOptions): #includeAll(vs/editor/browser/editorBrowser;editorCommon.=>;editorOptions.=>): #include(vs/editor/common/config/fontInfo): FontInfo, BareFontInfo diff --git a/build/monaco/package.json b/build/monaco/package.json index 1962694ce6..1ff3e4e72f 100644 --- a/build/monaco/package.json +++ b/build/monaco/package.json @@ -1,7 +1,7 @@ { "name": "monaco-editor-core", "private": true, - "version": "0.16.0", + "version": "0.18.0", "description": "A browser based code editor", "author": "Microsoft Corporation", "license": "MIT", diff --git a/build/npm/postinstall.js b/build/npm/postinstall.js index 0feda17b74..5a6a2bc2a3 100644 --- a/build/npm/postinstall.js +++ b/build/npm/postinstall.js @@ -70,6 +70,7 @@ runtime "${runtime}"`; } yarnInstall(`build`); // node modules required for build +yarnInstall('test/automation'); // node modules required for smoketest yarnInstall('test/smoke'); // node modules required for smoketest yarnInstallBuildDependencies(); // node modules for watching, specific to host node version, not electron diff --git a/build/package.json b/build/package.json index 9f6c4802c6..a1d7a65f69 100644 --- a/build/package.json +++ b/build/package.json @@ -24,9 +24,9 @@ "@types/pump": "^1.0.1", "@types/request": "^2.47.0", "@types/rimraf": "^2.0.2", + "@types/terser": "^3.12.0", "@types/through": "^0.0.29", "@types/through2": "^2.0.34", - "@types/uglify-es": "^3.0.0", "@types/underscore": "^1.8.9", "@types/xml2js": "0.0.33", "applicationinsights": "1.0.8", @@ -36,13 +36,15 @@ "github-releases": "^0.4.1", "gulp-bom": "^1.0.0", "gulp-sourcemaps": "^1.11.0", + "gulp-uglify": "^3.0.0", "iconv-lite": "0.4.23", "mime": "^1.3.4", "minimist": "^1.2.0", "request": "^2.85.0", + "terser": "4.3.1", "tslint": "^5.9.1", "service-downloader": "github:anthonydresser/service-downloader#0.1.7", - "typescript": "3.5.2", + "typescript": "3.6.2", "vsce": "1.48.0", "vscode-telemetry-extractor": "^1.5.4", "xml2js": "^0.4.17" diff --git a/build/yarn.lock b/build/yarn.lock index 0d865bebc3..fa92c53bdc 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -217,6 +217,13 @@ "@types/glob" "*" "@types/node" "*" +"@types/terser@^3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@types/terser/-/terser-3.12.0.tgz#25e020fe9a7a6ae92ce46261f00ced67de6c12ac" + integrity sha512-J0Wy8A7ULEqVJftkWhrXZbH0iBk4tYuTj0gBiiveKaY9deNi6cCsxl0ApJ27ojqwYv51bvEw85lOb8Wt4ng9zA== + dependencies: + terser "*" + "@types/through2@^2.0.34": version "2.0.34" resolved "https://registry.yarnpkg.com/@types/through2/-/through2-2.0.34.tgz#9c2a259a238dace2a05a2f8e94b786961bc27ac4" @@ -236,20 +243,6 @@ resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-2.3.2.tgz#e0d481d8bb282ad8a8c9e100ceb72c995fb5e709" integrity sha512-vOVmaruQG5EatOU/jM6yU2uCp3Lz6mK1P5Ztu4iJjfM4SVHU9XYktPUQtKlIXuahqXHdEyUarMrBEwg5Cwu+bA== -"@types/uglify-es@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/uglify-es/-/uglify-es-3.0.0.tgz#2c5e70b43c0e86643ac1c223f61df15fa0b87bc2" - integrity sha512-Oc/c7pGIQL0MVhC6g+VftWiDQethKsT4c3fQKYm6nOprkvkx9s1MLrnJprDTKlZL3ZJulMpCF9Qn7s6u3uCNxQ== - dependencies: - "@types/uglify-js" "*" - -"@types/uglify-js@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.3.tgz#801a5ca1dc642861f47c46d14b700ed2d610840b" - integrity sha512-MAT0BW2ruO0LhQKjvlipLGCF/Yx0y/cj+tT67tK3QIQDrM2+9R78HgJ54VlrE8AbfjYJJBCQCEPM5ZblPVTuww== - dependencies: - source-map "^0.6.1" - "@types/uglify-js@^2": version "2.6.32" resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-2.6.32.tgz#1b60906946fcf6ee4ceafa812d2b86f1358da904" @@ -433,6 +426,11 @@ array-differ@^3.0.0: resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== +array-each@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f" + integrity sha1-p5SvDAWrF1KEbudTofIRoFugxE8= + array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -686,6 +684,11 @@ buffer-fill@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + buffer@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.1.tgz#dd57fa0f109ac59c602479044dca7b8b3d0b71d6" @@ -869,6 +872,11 @@ commander@^2.12.1, commander@^2.8.1: resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== +commander@^2.20.0, commander@~2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + commander@~2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" @@ -1619,6 +1627,22 @@ gulp-sourcemaps@^1.11.0: through2 "2.X" vinyl "1.X" +gulp-uglify@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/gulp-uglify/-/gulp-uglify-3.0.2.tgz#5f5b2e8337f879ca9dec971feb1b82a5a87850b0" + integrity sha512-gk1dhB74AkV2kzqPMQBLA3jPoIAPd/nlNzP2XMDSG8XZrqnlCiDGAqC+rZOumzFvB5zOphlFh6yr3lgcAb/OOg== + dependencies: + array-each "^1.0.1" + extend-shallow "^3.0.2" + gulplog "^1.0.0" + has-gulplog "^0.1.0" + isobject "^3.0.1" + make-error-cause "^1.1.1" + safe-buffer "^5.1.2" + through2 "^2.0.0" + uglify-js "^3.0.5" + vinyl-sourcemaps-apply "^0.2.0" + gulp-util@^3.0.0: version "3.0.8" resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" @@ -2320,6 +2344,18 @@ make-dir@^1.0.0: dependencies: pify "^3.0.0" +make-error-cause@^1.1.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/make-error-cause/-/make-error-cause-1.2.2.tgz#df0388fcd0b37816dff0a5fb8108939777dcbc9d" + integrity sha1-3wOI/NCzeBbf8KX7gQiTl3fcvJ0= + dependencies: + make-error "^1.2.0" + +make-error@^1.2.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" + integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== + map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -3017,7 +3053,12 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== -safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@^5.1.2: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== @@ -3163,17 +3204,25 @@ source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: source-map-url "^0.4.0" urix "^0.1.0" +source-map-support@~0.5.12: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@^0.5.6: +source-map@^0.5.1, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@^0.6.1, source-map@~0.6.0: +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -3323,6 +3372,24 @@ tar@^4: safe-buffer "^5.1.2" yallist "^3.0.2" +terser@*: + version "4.2.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.2.1.tgz#1052cfe17576c66e7bc70fcc7119f22b155bdac1" + integrity sha512-cGbc5utAcX4a9+2GGVX4DsenG6v0x3glnDi5hx8816X1McEAwPlPgRtXPJzSBsbpILxZ8MQMT0KvArLuE0HP5A== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + +terser@4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.3.1.tgz#09820bcb3398299c4b48d9a86aefc65127d0ed65" + integrity sha512-pnzH6dnFEsR2aa2SJaKb1uSCl3QmIsJ8dEkj0Fky+2AwMMcC9doMqLOQIH6wVTEKaVfKVvLSk5qxPBEZT9mywg== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + through2@2.X, through2@^2.0.0, through2@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" @@ -3475,10 +3542,10 @@ typed-rest-client@^0.9.0: tunnel "0.0.4" underscore "1.8.3" -typescript@3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.2.tgz#a09e1dc69bc9551cadf17dba10ee42cf55e5d56c" - integrity sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA== +typescript@3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.2.tgz#105b0f1934119dde543ac8eb71af3a91009efe54" + integrity sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw== typescript@^3.0.1: version "3.5.3" @@ -3495,6 +3562,14 @@ uc.micro@^1.0.1, uc.micro@^1.0.5: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" integrity sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg== +uglify-js@^3.0.5: + version "3.6.0" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5" + integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg== + dependencies: + commander "~2.20.0" + source-map "~0.6.1" + unbzip2-stream@^1.0.9: version "1.3.3" resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz#d156d205e670d8d8c393e1c02ebd506422873f6a" @@ -3590,6 +3665,13 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +vinyl-sourcemaps-apply@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705" + integrity sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU= + dependencies: + source-map "^0.5.1" + vinyl@1.X: version "1.2.0" resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" @@ -3632,9 +3714,9 @@ vsce@1.48.0: yazl "^2.2.2" vscode-ripgrep@^1.5.6: - version "1.5.6" - resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.6.tgz#93bf5c99ca5f8248950a305e224f6ca153c30af4" - integrity sha512-WRIM9XpUj6dsfdAmuI3ANbmT1ysPUVsYy/2uCLDHJa9kbiB4T7uGvFnnc0Rgx2qQnyRAwL7PeWaFgUljPPxf2g== + version "1.5.7" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.7.tgz#acb6b548af488a4bca5d0f1bb5faf761343289ce" + integrity sha512-/Vsz/+k8kTvui0q3O74pif9FK0nKopgFTiGNVvxicZANxtSA8J8gUE9GQ/4dpi7D/2yI/YVORszwVskFbz46hQ== vscode-telemetry-extractor@^1.5.4: version "1.5.4" diff --git a/cglicenses.json b/cglicenses.json index 15b3036268..df57f699bd 100644 --- a/cglicenses.json +++ b/cglicenses.json @@ -48,6 +48,7 @@ }, { // Reason: The npm module does not contain a repository field. + // waiting for https://github.com/xtermjs/xterm.js/issues/2395 "name": "xterm-addon-search", "fullLicenseText": [ "Copyright (c) 2017, The xterm.js authors (https://github.com/xtermjs/xterm.js)", @@ -73,6 +74,7 @@ }, { // Reason: The npm module does not contain a repository field. + // waiting for https://github.com/xtermjs/xterm.js/issues/2395 "name": "xterm-addon-web-links", "fullLicenseText": [ "Copyright (c) 2017, The xterm.js authors (https://github.com/xtermjs/xterm.js)", diff --git a/cgmanifest.json b/cgmanifest.json index 5ba2e16626..d26f37b620 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -60,12 +60,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "3d4d6454007f14fa9a5f0e1fa49206fb91b676cc" + "commitHash": "4e4c7527c63fcf27dffaeb58bde996b8d859c0ed" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "4.2.9" + "version": "4.2.10" }, { "component": { diff --git a/extensions/admin-tool-ext-win/src/config.json b/extensions/admin-tool-ext-win/config.json similarity index 100% rename from extensions/admin-tool-ext-win/src/config.json rename to extensions/admin-tool-ext-win/config.json diff --git a/extensions/admin-tool-ext-win/src/main.ts b/extensions/admin-tool-ext-win/src/main.ts index d8e518f1ef..23b3ad10ee 100644 --- a/extensions/admin-tool-ext-win/src/main.ts +++ b/extensions/admin-tool-ext-win/src/main.ts @@ -10,8 +10,10 @@ import * as vscode from 'vscode'; import { TelemetryReporter, TelemetryViews } from './telemetry'; import { doubleEscapeSingleQuotes, backEscapeDoubleQuotes, getTelemetryErrorType } from './utils'; import { ChildProcess, exec } from 'child_process'; +import { promisify } from 'util'; +import { readFile } from 'fs'; + const localize = nls.loadMessageBundle(); -const ssmsMinVer = JSON.parse(JSON.stringify(require('./config.json'))).version; let exePath: string; const runningProcesses: Map = new Map(); @@ -66,6 +68,8 @@ export interface LaunchSsmsDialogParams { export async function activate(context: vscode.ExtensionContext): Promise { // This is for Windows-specific support so do nothing on other platforms if (process.platform === 'win32') { + const rawConfig = await promisify(readFile)(path.join(context.extensionPath, 'config.json')); + const ssmsMinVer = JSON.parse(rawConfig.toString()).version; exePath = path.join(context.extensionPath, 'ssmsmin', 'Windows', ssmsMinVer, 'ssmsmin.exe'); registerCommands(context); } @@ -259,4 +263,4 @@ export async function buildUrn(node: azdata.objectexplorer.ObjectExplorerNode): } return ['Server'].concat(urnNodes).join('/'); -} \ No newline at end of file +} diff --git a/extensions/agent/package.json b/extensions/agent/package.json index 5be81a05b7..59535c738a 100644 --- a/extensions/agent/package.json +++ b/extensions/agent/package.json @@ -84,7 +84,7 @@ "mocha-junit-reporter": "^1.17.0", "mocha-multi-reporters": "^1.1.7", "@types/mocha": "^5.2.5", - "@types/node": "^8.10.25", + "@types/node": "^10.14.8", "mocha": "^5.2.0", "should": "^13.2.1", "typemoq": "^2.1.0", diff --git a/extensions/agent/src/dialogs/jobStepDialog.ts b/extensions/agent/src/dialogs/jobStepDialog.ts index fbe27860bf..d06c769179 100644 --- a/extensions/agent/src/dialogs/jobStepDialog.ts +++ b/extensions/agent/src/dialogs/jobStepDialog.ts @@ -259,9 +259,9 @@ export class JobStepDialog extends AgentDialog { title: this.CommandLabelString, actions: [this.openButton, this.parseButton] }], { - horizontal: false, - componentWidth: 420 - }).component(); + horizontal: false, + componentWidth: 420 + }).component(); this.typeDropdown.onValueChanged((type) => { switch (type.selected) { case (JobStepDialog.TSQLScript): @@ -375,8 +375,8 @@ export class JobStepDialog extends AgentDialog { component: this.userInputBox, title: this.RunAsUserLabel }], { - componentWidth: 400 - }).component(); + componentWidth: 400 + }).component(); let formWrapper = view.modelBuilder.loadingComponent().withItem(formModel).component(); formWrapper.loading = false; @@ -419,9 +419,9 @@ export class JobStepDialog extends AgentDialog { component: this.retryAttemptsBox, title: this.RetryAttemptsLabel }], { - horizontal: false, - componentWidth: '100%' - }) + horizontal: false, + componentWidth: '100%' + }) .component(); let retryIntervalContainer = view.modelBuilder.formContainer() @@ -430,8 +430,8 @@ export class JobStepDialog extends AgentDialog { component: this.retryIntervalBox, title: this.RetryIntervalLabel }], { - horizontal: false - }) + horizontal: false + }) .component(); let retryFlexContainer = view.modelBuilder.flexContainer() @@ -574,4 +574,4 @@ export class JobStepDialog extends AgentDialog { return validationResult.valid; }); } -} \ No newline at end of file +} diff --git a/extensions/agent/yarn.lock b/extensions/agent/yarn.lock index 1aa3c07300..2f4edac013 100644 --- a/extensions/agent/yarn.lock +++ b/extensions/agent/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.6.tgz#b8622d50557dd155e9f2f634b7d68fd38de5e94b" integrity sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw== -"@types/node@^8.10.25": - version "8.10.45" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.45.tgz#4c49ba34106bc7dced77ff6bae8eb6543cde8351" - integrity sha512-tGVTbA+i3qfXsLbq9rEq/hezaHY55QxQLeXQL2ejNgFAxxrgu8eMmYIOsRcl7hN1uTLVsKOOYacV/rcJM3sfgQ== +"@types/node@^10.14.8": + version "10.14.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.17.tgz#b96d4dd3e427382482848948041d3754d40fd5ce" + integrity sha512-p/sGgiPaathCfOtqu2fx5Mu1bcjuP8ALFg4xpGgNkcin7LwRyzUKniEHBKdcE1RPsenq5JVPIpMTJSygLboygQ== ajv@^6.5.5: version "6.10.0" diff --git a/extensions/cms/package.json b/extensions/cms/package.json index 496f80b725..bd8ea3f328 100644 --- a/extensions/cms/package.json +++ b/extensions/cms/package.json @@ -627,7 +627,7 @@ }, "devDependencies": { "@types/mocha": "^5.2.5", - "@types/node": "^8.0.24", + "@types/node": "^10.14.8", "mocha": "^5.2.0", "should": "^13.2.1", "vscode": "^1.1.26", diff --git a/extensions/cms/yarn.lock b/extensions/cms/yarn.lock index c3c2c8d8ff..6db77cbebb 100644 --- a/extensions/cms/yarn.lock +++ b/extensions/cms/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.5.tgz#8a4accfc403c124a0bafe8a9fc61a05ec1032073" integrity sha512-lAVp+Kj54ui/vLUFxsJTMtWvZraZxum3w3Nwkble2dNuV5VnPA+Mi2oGX9XYJAaIvZi3tn3cbjS/qcJXRb6Bww== -"@types/node@^8.0.24": - version "8.10.36" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.36.tgz#eac05d576fbcd0b4ea3c912dc58c20475c08d9e4" - integrity sha512-SL6KhfM7PTqiFmbCW3eVNwVBZ+88Mrzbuvn9olPsfv43mbiWaFY+nRcz/TGGku0/lc2FepdMbImdMY1JrQ+zbw== +"@types/node@^10.14.8": + version "10.14.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.17.tgz#b96d4dd3e427382482848948041d3754d40fd5ce" + integrity sha512-p/sGgiPaathCfOtqu2fx5Mu1bcjuP8ALFg4xpGgNkcin7LwRyzUKniEHBKdcE1RPsenq5JVPIpMTJSygLboygQ== ajv@^5.3.0: version "5.5.2" diff --git a/extensions/dacpac/src/wizard/pages/deployConfigPage.ts b/extensions/dacpac/src/wizard/pages/deployConfigPage.ts index 3e2f19c681..57a3af68ee 100644 --- a/extensions/dacpac/src/wizard/pages/deployConfigPage.ts +++ b/extensions/dacpac/src/wizard/pages/deployConfigPage.ts @@ -49,9 +49,9 @@ export class DeployConfigPage extends DacFxConfigPage { radioButtons, this.databaseDropdownComponent ], { - horizontal: true, - componentWidth: 400 - }); + horizontal: true, + componentWidth: 400 + }); this.form = this.formBuilder.component(); await this.view.initializeModel(this.form); diff --git a/extensions/dacpac/src/wizard/pages/deployPlanPage.ts b/extensions/dacpac/src/wizard/pages/deployPlanPage.ts index c620f79384..f8021a8bd1 100644 --- a/extensions/dacpac/src/wizard/pages/deployPlanPage.ts +++ b/extensions/dacpac/src/wizard/pages/deployPlanPage.ts @@ -69,8 +69,8 @@ export class DeployPlanPage extends DacFxConfigPage { }, this.dataLossComponentGroup ], { - horizontal: true, - }); + horizontal: true, + }); this.form = this.formBuilder.component(); await this.view.initializeModel(this.form); diff --git a/extensions/dacpac/src/wizard/pages/exportConfigPage.ts b/extensions/dacpac/src/wizard/pages/exportConfigPage.ts index c2b18dd039..d2e5226f8b 100644 --- a/extensions/dacpac/src/wizard/pages/exportConfigPage.ts +++ b/extensions/dacpac/src/wizard/pages/exportConfigPage.ts @@ -39,9 +39,9 @@ export class ExportConfigPage extends DacFxConfigPage { databaseComponent, fileBrowserComponent, ], { - horizontal: true, - componentWidth: 400 - }).component(); + horizontal: true, + componentWidth: 400 + }).component(); await this.view.initializeModel(this.form); return true; } diff --git a/extensions/dacpac/src/wizard/pages/extractConfigPage.ts b/extensions/dacpac/src/wizard/pages/extractConfigPage.ts index e4f34edaf8..5b4deb6d03 100644 --- a/extensions/dacpac/src/wizard/pages/extractConfigPage.ts +++ b/extensions/dacpac/src/wizard/pages/extractConfigPage.ts @@ -42,9 +42,9 @@ export class ExtractConfigPage extends DacFxConfigPage { versionComponent, fileBrowserComponent, ], { - horizontal: true, - componentWidth: 400 - }).component(); + horizontal: true, + componentWidth: 400 + }).component(); await this.view.initializeModel(this.form); return true; } diff --git a/extensions/dacpac/src/wizard/pages/importConfigPage.ts b/extensions/dacpac/src/wizard/pages/importConfigPage.ts index 3a5e5f7c46..6bc4283c06 100644 --- a/extensions/dacpac/src/wizard/pages/importConfigPage.ts +++ b/extensions/dacpac/src/wizard/pages/importConfigPage.ts @@ -41,9 +41,9 @@ export class ImportConfigPage extends DacFxConfigPage { serverComponent, databaseComponent, ], { - horizontal: true, - componentWidth: 400 - }).component(); + horizontal: true, + componentWidth: 400 + }).component(); await this.view.initializeModel(this.form); return true; } diff --git a/extensions/dacpac/src/wizard/pages/selectOperationpage.ts b/extensions/dacpac/src/wizard/pages/selectOperationpage.ts index c7907496a6..68a216505e 100644 --- a/extensions/dacpac/src/wizard/pages/selectOperationpage.ts +++ b/extensions/dacpac/src/wizard/pages/selectOperationpage.ts @@ -51,8 +51,8 @@ export class SelectOperationPage extends BasePage { importComponent, exportComponent ], { - horizontal: true - }).component(); + horizontal: true + }).component(); await this.view.initializeModel(this.form); this.instance.setDoneButton(Operation.deploy); diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 7d90b4b15f..b4cbdad098 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -73,7 +73,7 @@ "config.autofetch": "When enabled, commits will automatically be fetched from the default remote of the current Git repository.", "config.autofetchPeriod": "Duration in seconds between each automatic git fetch, when `git.autofetch` is enabled.", "config.confirmSync": "Confirm before synchronizing git repositories.", - "config.countBadge": "Controls the git badge counter.", + "config.countBadge": "Controls the Git count badge.", "config.countBadge.all": "Count all changes.", "config.countBadge.tracked": "Count only tracked changes.", "config.countBadge.off": "Turn off counter.", diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 6b51af28b6..24afc46b9c 100755 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1260,7 +1260,7 @@ export class CommandCenter { if (documents.length > 0) { const message = documents.length === 1 - ? localize('unsaved files single', "The following file is unsaved and will not be included in the commit if you proceed: {0}.\n\nWould you like to save it before committing?", path.basename(documents[0].uri.fsPath)) + ? localize('unsaved files single', "The following file has unsaved changes which won't be included in the commit if you proceed: {0}.\n\nWould you like to save it before committing?", path.basename(documents[0].uri.fsPath)) : localize('unsaved files', "There are {0} unsaved files.\n\nWould you like to save them before committing?", documents.length); const saveAndCommit = localize('save and commit', "Save All & Commit"); const commit = localize('commit', "Commit Anyway"); diff --git a/extensions/git/src/decorationProvider.ts b/extensions/git/src/decorationProvider.ts index 4623328768..e022411cc9 100644 --- a/extensions/git/src/decorationProvider.ts +++ b/extensions/git/src/decorationProvider.ts @@ -3,13 +3,13 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { window, workspace, Uri, Disposable, Event, EventEmitter, DecorationData, DecorationProvider, ThemeColor } from 'vscode'; +import { window, workspace, Uri, Disposable, Event, EventEmitter, Decoration, DecorationProvider, ThemeColor } from 'vscode'; import * as path from 'path'; import { Repository, GitResourceGroup } from './repository'; import { Model } from './model'; import { debounce } from './decorators'; import { filterEvent, dispose, anyEvent, fireEvent } from './util'; -import { GitErrorCodes, Status } from './api/git'; +import { GitErrorCodes } from './api/git'; type Callback = { resolve: (status: boolean) => void, reject: (err: any) => void }; @@ -29,7 +29,7 @@ class GitIgnoreDecorationProvider implements DecorationProvider { this.disposables.push(window.registerDecorationProvider(this)); } - provideDecoration(uri: Uri): Promise { + provideDecoration(uri: Uri): Promise { const repository = this.model.getRepository(uri); if (!repository) { @@ -48,7 +48,7 @@ class GitIgnoreDecorationProvider implements DecorationProvider { this.checkIgnoreSoon(); }).then(ignored => { if (ignored) { - return { + return { priority: 3, color: new ThemeColor('gitDecoration.ignoredResourceForeground') }; @@ -89,7 +89,7 @@ class GitIgnoreDecorationProvider implements DecorationProvider { class GitDecorationProvider implements DecorationProvider { - private static SubmoduleDecorationData: DecorationData = { + private static SubmoduleDecorationData: Decoration = { title: 'Submodule', letter: 'S', color: new ThemeColor('gitDecoration.submoduleResourceForeground') @@ -99,7 +99,7 @@ class GitDecorationProvider implements DecorationProvider { readonly onDidChangeDecorations: Event = this._onDidChangeDecorations.event; private disposables: Disposable[] = []; - private decorations = new Map(); + private decorations = new Map(); constructor(private repository: Repository) { this.disposables.push( @@ -109,7 +109,7 @@ class GitDecorationProvider implements DecorationProvider { } private onDidRunGitStatus(): void { - let newDecorations = new Map(); + let newDecorations = new Map(); this.collectSubmoduleDecorationData(newDecorations); this.collectDecorationData(this.repository.indexGroup, newDecorations); @@ -121,25 +121,22 @@ class GitDecorationProvider implements DecorationProvider { this._onDidChangeDecorations.fire([...uris.values()].map(value => Uri.parse(value, true))); } - private collectDecorationData(group: GitResourceGroup, bucket: Map): void { + private collectDecorationData(group: GitResourceGroup, bucket: Map): void { group.resourceStates.forEach(r => { - if (r.resourceDecoration - && r.type !== Status.DELETED - && r.type !== Status.INDEX_DELETED - ) { + if (r.resourceDecoration) { // not deleted and has a decoration bucket.set(r.original.toString(), r.resourceDecoration); } }); } - private collectSubmoduleDecorationData(bucket: Map): void { + private collectSubmoduleDecorationData(bucket: Map): void { for (const submodule of this.repository.submodules) { bucket.set(Uri.file(path.join(this.repository.root, submodule.path)).toString(), GitDecorationProvider.SubmoduleDecorationData); } } - provideDecoration(uri: Uri): DecorationData | undefined { + provideDecoration(uri: Uri): Decoration | undefined { return this.decorations.get(uri.toString()); } diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 01877f4362..a1509b746a 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -1628,7 +1628,7 @@ export class Repository { const args = ['for-each-ref', '--format', '%(refname) %(objectname)']; if (opts && opts.sort && opts.sort !== 'alphabetically') { - args.push('--sort', opts.sort); + args.push('--sort', `-${opts.sort}`); } const result = await this.run(args); @@ -1766,7 +1766,7 @@ export class Repository { } const raw = await readfile(templatePath, 'utf8'); - return raw.replace(/\n?#.*/g, ''); + return raw.replace(/^\s*#.*$\n?/gm, ''); } catch (err) { return ''; diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 0660c83f45..d7b0c671b0 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { commands, Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, SourceControlInputBoxValidation, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento, SourceControlInputBoxValidationType, OutputChannel, LogLevel, env, ProgressOptions, CancellationToken } from 'vscode'; +import { commands, Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, SourceControlInputBoxValidation, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, Decoration, Memento, SourceControlInputBoxValidationType, OutputChannel, LogLevel, env, ProgressOptions, CancellationToken } from 'vscode'; import { Repository as BaseRepository, Commit, Stash, GitError, Submodule, CommitOptions, ForcePushMode } from './git'; import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant, IDisposable, onceEvent, EmptyDisposable, debounceEvent, combinedDisposable } from './util'; import { memoize, throttle, debounce } from './decorators'; @@ -157,10 +157,7 @@ export class Resource implements SourceControlResourceState { const tooltip = this.tooltip; const strikeThrough = this.strikeThrough; const faded = this.faded; - const letter = this.letter; - const color = this.color; - - return { strikeThrough, faded, tooltip, light, dark, letter, color, source: 'git.resource' /*todo@joh*/ }; + return { strikeThrough, faded, tooltip, light, dark }; } get letter(): string { @@ -247,12 +244,12 @@ export class Resource implements SourceControlResourceState { } } - get resourceDecoration(): DecorationData { + get resourceDecoration(): Decoration { const title = this.tooltip; const letter = this.letter; const color = this.color; const priority = this.priority; - return { bubble: true, source: 'git.resource', title, letter, color, priority }; + return { bubble: true, title, letter, color, priority }; } constructor( diff --git a/extensions/git/src/statusbar.ts b/extensions/git/src/statusbar.ts index 67c5bf0c72..2d2288f3fa 100644 --- a/extensions/git/src/statusbar.ts +++ b/extensions/git/src/statusbar.ts @@ -71,6 +71,7 @@ class SyncStatusBar { const onEnablementChange = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.enableStatusBarSync')); onEnablementChange(this.updateEnablement, this, this.disposables); + this.updateEnablement(); this._onDidChange.fire(); } diff --git a/extensions/image-preview/.vscodeignore b/extensions/image-preview/.vscodeignore new file mode 100644 index 0000000000..30d948fbc6 --- /dev/null +++ b/extensions/image-preview/.vscodeignore @@ -0,0 +1,10 @@ +test/** +src/** +tsconfig.json +out/test/** +out/** +extension.webpack.config.js +cgmanifest.json +yarn.lock +preview-src/** +webpack.config.js diff --git a/extensions/image-preview/README.md b/extensions/image-preview/README.md new file mode 100644 index 0000000000..e8664c77a9 --- /dev/null +++ b/extensions/image-preview/README.md @@ -0,0 +1,3 @@ +# Image Preview + +**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled. diff --git a/extensions/image-preview/extension.webpack.config.js b/extensions/image-preview/extension.webpack.config.js new file mode 100644 index 0000000000..f35561d9f2 --- /dev/null +++ b/extensions/image-preview/extension.webpack.config.js @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +'use strict'; + +const withDefaults = require('../shared.webpack.config'); + +module.exports = withDefaults({ + context: __dirname, + resolve: { + mainFields: ['module', 'main'] + }, + entry: { + extension: './src/extension.ts', + } +}); diff --git a/extensions/image-preview/media/main.css b/extensions/image-preview/media/main.css new file mode 100644 index 0000000000..9a4844ecd2 --- /dev/null +++ b/extensions/image-preview/media/main.css @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +html, body { + height: 100%; + max-height: 100%; +} + + +body img { + max-width: none; + max-height: none; +} + +.container:focus { + outline: none !important; +} + +.container { + padding: 5px 0 0 10px; + box-sizing: border-box; + user-select: none; +} + +.container.image { + padding: 0; + display: flex; + box-sizing: border-box; +} + +.container.image img { + padding: 0; + background-position: 0 0, 8px 8px; + background-size: 16px 16px; +} + +.container.image img { + background-image: + linear-gradient(45deg, rgb(230, 230, 230) 25%, transparent 25%, transparent 75%, rgb(230, 230, 230) 75%, rgb(230, 230, 230)), + linear-gradient(45deg, rgb(230, 230, 230) 25%, transparent 25%, transparent 75%, rgb(230, 230, 230) 75%, rgb(230, 230, 230)); +} + +.vscode-dark.container.image img { + background-image: + linear-gradient(45deg, rgb(20, 20, 20) 25%, transparent 25%, transparent 75%, rgb(20, 20, 20) 75%, rgb(20, 20, 20)), + linear-gradient(45deg, rgb(20, 20, 20) 25%, transparent 25%, transparent 75%, rgb(20, 20, 20) 75%, rgb(20, 20, 20)); +} + +.container img.pixelated { + image-rendering: pixelated; +} + +.container img.scale-to-fit { + max-width: calc(100% - 20px); + max-height: calc(100% - 20px); + object-fit: contain; +} + +.container img { + margin: auto; +} + +.container.zoom-in { + cursor: zoom-in; +} + +.container.zoom-out { + cursor: zoom-out; +} + +.container .embedded-link, +.container .embedded-link:hover { + cursor: pointer; + text-decoration: underline; + margin-left: 5px; +} diff --git a/extensions/image-preview/media/main.js b/extensions/image-preview/media/main.js new file mode 100644 index 0000000000..f2bb9e4eb7 --- /dev/null +++ b/extensions/image-preview/media/main.js @@ -0,0 +1,258 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// @ts-check +"use strict"; + +(function () { + /** + * @param {number} value + * @param {number} min + * @param {number} max + * @return {number} + */ + function clamp(value, min, max) { + return Math.min(Math.max(value, min), max); + } + + function getSettings() { + const element = document.getElementById('image-preview-settings'); + if (element) { + const data = element.getAttribute('data-settings'); + if (data) { + return JSON.parse(data); + } + } + + throw new Error(`Could not load settings`); + } + + /** + * Enable image-rendering: pixelated for images scaled by more than this. + */ + const PIXELATION_THRESHOLD = 3; + + const SCALE_PINCH_FACTOR = 0.075; + const MAX_SCALE = 20; + const MIN_SCALE = 0.1; + + const zoomLevels = [ + 0.1, + 0.2, + 0.3, + 0.4, + 0.5, + 0.6, + 0.7, + 0.8, + 0.9, + 1, + 1.5, + 2, + 3, + 5, + 7, + 10, + 15, + 20 + ]; + + const isMac = getSettings().isMac; + + const vscode = acquireVsCodeApi(); + + const initialState = vscode.getState() || { scale: 'fit', offsetX: 0, offsetY: 0 }; + + // State + let scale = initialState.scale; + let ctrlPressed = false; + let altPressed = false; + + // Elements + const container = /** @type {HTMLElement} */(document.querySelector('body')); + const image = document.querySelector('img'); + + function updateScale(newScale) { + if (!image || !image.parentElement) { + return; + } + + if (newScale === 'fit') { + scale = 'fit'; + image.classList.add('scale-to-fit'); + image.classList.remove('pixelated'); + image.style.minWidth = 'auto'; + image.style.width = 'auto'; + vscode.setState(undefined); + } else { + const oldWidth = image.width; + const oldHeight = image.height; + + scale = clamp(newScale, MIN_SCALE, MAX_SCALE); + if (scale >= PIXELATION_THRESHOLD) { + image.classList.add('pixelated'); + } else { + image.classList.remove('pixelated'); + } + + const { scrollTop, scrollLeft } = image.parentElement; + const dx = (scrollLeft + image.parentElement.clientWidth / 2) / image.parentElement.scrollWidth; + const dy = (scrollTop + image.parentElement.clientHeight / 2) / image.parentElement.scrollHeight; + + image.classList.remove('scale-to-fit'); + image.style.minWidth = `${(image.naturalWidth * scale)}px`; + image.style.width = `${(image.naturalWidth * scale)}px`; + + const newWidth = image.width; + const scaleFactor = (newWidth - oldWidth) / oldWidth; + + const newScrollLeft = ((oldWidth * scaleFactor * dx) + scrollLeft); + const newScrollTop = ((oldHeight * scaleFactor * dy) + scrollTop); + // scrollbar.setScrollPosition({ + // scrollLeft: newScrollLeft, + // scrollTop: newScrollTop, + // }); + + vscode.setState({ scale: scale, offsetX: newScrollLeft, offsetY: newScrollTop }); + } + + vscode.postMessage({ + type: 'zoom', + value: scale + }); + } + + function firstZoom() { + if (!image) { + return; + } + + scale = image.clientWidth / image.naturalWidth; + updateScale(scale); + } + + window.addEventListener('keydown', (/** @type {KeyboardEvent} */ e) => { + if (!image) { + return; + } + ctrlPressed = e.ctrlKey; + altPressed = e.altKey; + + if (isMac ? altPressed : ctrlPressed) { + container.classList.remove('zoom-in'); + container.classList.add('zoom-out'); + } + }); + + window.addEventListener('keyup', (/** @type {KeyboardEvent} */ e) => { + if (!image) { + return; + } + + ctrlPressed = e.ctrlKey; + altPressed = e.altKey; + + if (!(isMac ? altPressed : ctrlPressed)) { + container.classList.remove('zoom-out'); + container.classList.add('zoom-in'); + } + }); + + container.addEventListener('click', (/** @type {MouseEvent} */ e) => { + if (!image) { + return; + } + + if (e.button !== 0) { + return; + } + + // left click + if (scale === 'fit') { + firstZoom(); + } + + if (!(isMac ? altPressed : ctrlPressed)) { // zoom in + let i = 0; + for (; i < zoomLevels.length; ++i) { + if (zoomLevels[i] > scale) { + break; + } + } + updateScale(zoomLevels[i] || MAX_SCALE); + } else { + let i = zoomLevels.length - 1; + for (; i >= 0; --i) { + if (zoomLevels[i] < scale) { + break; + } + } + updateScale(zoomLevels[i] || MIN_SCALE); + } + }); + + container.addEventListener('wheel', (/** @type {WheelEvent} */ e) => { + if (!image) { + return; + } + + const isScrollWheelKeyPressed = isMac ? altPressed : ctrlPressed; + if (!isScrollWheelKeyPressed && !e.ctrlKey) { // pinching is reported as scroll wheel + ctrl + return; + } + + e.preventDefault(); + e.stopPropagation(); + + if (scale === 'fit') { + firstZoom(); + } + + let delta = e.deltaY > 0 ? 1 : -1; + updateScale(scale * (1 - delta * SCALE_PINCH_FACTOR)); + }); + + window.addEventListener('scroll', () => { + if (!image || !image.parentElement || scale === 'fit') { + return; + } + + const entry = vscode.getState(); + if (entry) { + vscode.setState({ scale: entry.scale, offsetX: window.scrollX, offsetY: window.scrollY }); + } + }); + + container.classList.add('image'); + container.classList.add('zoom-in'); + + image.classList.add('scale-to-fit'); + image.style.visibility = 'hidden'; + + image.addEventListener('load', () => { + if (!image) { + return; + } + + vscode.postMessage({ + type: 'size', + value: `${image.naturalWidth}x${image.naturalHeight}`, + }); + + image.style.visibility = 'visible'; + updateScale(scale); + + if (initialState.scale !== 'fit') { + window.scrollTo(initialState.offsetX, initialState.offsetY); + } + }); + + window.addEventListener('message', e => { + switch (e.data.type) { + case 'setScale': + updateScale(e.data.scale); + break; + } + }); +}()); diff --git a/extensions/image-preview/package.json b/extensions/image-preview/package.json new file mode 100644 index 0000000000..aad1416c7b --- /dev/null +++ b/extensions/image-preview/package.json @@ -0,0 +1,43 @@ +{ + "name": "image-preview", + "displayName": "%displayName%", + "description": "%description%", + "version": "1.0.0", + "publisher": "vscode", + "enableProposedApi": true, + "license": "MIT", + "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "engines": { + "vscode": "^1.39.0" + }, + "main": "./out/extension", + "categories": [ + "Other" + ], + "activationEvents": [ + "onWebviewEditor:imagePreview.previewEditor" + ], + "contributes": { + "webviewEditors": [ + { + "viewType": "imagePreview.previewEditor", + "displayName": "%webviewEditors.displayName%", + "selector": [ + { + "filenamePattern": "*.{jpg,jpe,jpeg,png,bmp,gif,ico,tga,tif,tiff,webp}" + } + ] + } + ] + }, + "scripts": { + "compile": "gulp compile-extension:image-preview", + "watch": "npm run build-preview && gulp watch-extension:image-preview", + "vscode:prepublish": "npm run build-ext", + "build-ext": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:image-preview ./tsconfig.json" + }, + "dependencies": { + "vscode-extension-telemetry": "0.1.1", + "vscode-nls": "^4.0.0" + } +} diff --git a/extensions/image-preview/package.nls.json b/extensions/image-preview/package.nls.json new file mode 100644 index 0000000000..78c753d1d5 --- /dev/null +++ b/extensions/image-preview/package.nls.json @@ -0,0 +1,5 @@ +{ + "displayName": "Image Preview", + "description": "Previews images.", + "webviewEditors.displayName": "Image Preview" +} diff --git a/extensions/image-preview/src/dispose.ts b/extensions/image-preview/src/dispose.ts new file mode 100644 index 0000000000..33c2a708d8 --- /dev/null +++ b/extensions/image-preview/src/dispose.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +export function disposeAll(disposables: vscode.Disposable[]) { + while (disposables.length) { + const item = disposables.pop(); + if (item) { + item.dispose(); + } + } +} + +export abstract class Disposable { + private _isDisposed = false; + + protected _disposables: vscode.Disposable[] = []; + + public dispose(): any { + if (this._isDisposed) { + return; + } + this._isDisposed = true; + disposeAll(this._disposables); + } + + protected _register(value: T): T { + if (this._isDisposed) { + value.dispose(); + } else { + this._disposables.push(value); + } + return value; + } + + protected get isDisposed() { + return this._isDisposed; + } +} diff --git a/extensions/image-preview/src/extension.ts b/extensions/image-preview/src/extension.ts new file mode 100644 index 0000000000..7d4d49f717 --- /dev/null +++ b/extensions/image-preview/src/extension.ts @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { Preview } from './preview'; +import { SizeStatusBarEntry } from './sizeStatusBarEntry'; +import { ZoomStatusBarEntry } from './zoomStatusBarEntry'; + +export function activate(context: vscode.ExtensionContext) { + const extensionRoot = vscode.Uri.file(context.extensionPath); + + const sizeStatusBarEntry = new SizeStatusBarEntry(); + context.subscriptions.push(sizeStatusBarEntry); + + const zoomStatusBarEntry = new ZoomStatusBarEntry(); + context.subscriptions.push(zoomStatusBarEntry); + + context.subscriptions.push(vscode.window.registerWebviewEditorProvider( + Preview.viewType, + { + async resolveWebviewEditor(resource: vscode.Uri, editor: vscode.WebviewEditor): Promise { + // tslint:disable-next-line: no-unused-expression + new Preview(extensionRoot, resource, editor, sizeStatusBarEntry, zoomStatusBarEntry); + } + })); +} diff --git a/extensions/image-preview/src/preview.ts b/extensions/image-preview/src/preview.ts new file mode 100644 index 0000000000..97d4d7c29b --- /dev/null +++ b/extensions/image-preview/src/preview.ts @@ -0,0 +1,113 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { SizeStatusBarEntry } from './sizeStatusBarEntry'; +import { ZoomStatusBarEntry } from './zoomStatusBarEntry'; +import { Disposable } from './dispose'; + +export class Preview extends Disposable { + + public static readonly viewType = 'imagePreview.previewEditor'; + + private _active = true; + + constructor( + private readonly extensionRoot: vscode.Uri, + resource: vscode.Uri, + private readonly webviewEditor: vscode.WebviewEditor, + private readonly sizeStatusBarEntry: SizeStatusBarEntry, + private readonly zoomStatusBarEntry: ZoomStatusBarEntry, + ) { + super(); + const resourceRoot = resource.with({ + path: resource.path.replace(/\/[^\/]+?\.\w+$/, '/'), + }); + + webviewEditor.webview.options = { + enableScripts: true, + localResourceRoots: [ + resourceRoot, + extensionRoot, + ] + }; + + webviewEditor.webview.html = this.getWebiewContents(webviewEditor, resource); + + this._register(webviewEditor.webview.onDidReceiveMessage(message => { + switch (message.type) { + case 'size': + { + this.sizeStatusBarEntry.update(message.value); + break; + } + case 'zoom': + { + this.zoomStatusBarEntry.update(message.value); + break; + } + } + })); + + this._register(zoomStatusBarEntry.onDidChangeScale(e => { + this.webviewEditor.webview.postMessage({ type: 'setScale', scale: e.scale }); + })); + + this._register(webviewEditor.onDidChangeViewState(() => { + this.update(); + })); + this._register(webviewEditor.onDidDispose(() => { + if (this._active) { + this.sizeStatusBarEntry.hide(); + this.zoomStatusBarEntry.hide(); + } + })); + this.update(); + } + + private update() { + this._active = this.webviewEditor.active; + if (this._active) { + this.sizeStatusBarEntry.show(); + this.zoomStatusBarEntry.show(); + } else { + this.sizeStatusBarEntry.hide(); + this.zoomStatusBarEntry.hide(); + } + } + + private getWebiewContents(webviewEditor: vscode.WebviewEditor, resource: vscode.Uri): string { + const settings = { + isMac: process.platform === 'darwin' + }; + + return /* html */` + + + + + + Image Preview + + + + + + + + +`; + } + + private extensionResource(path: string) { + return this.webviewEditor.webview.asWebviewUri(this.extensionRoot.with({ + path: this.extensionRoot.path + path + })); + } +} + +function escapeAttribute(value: string | vscode.Uri): string { + return value.toString().replace(/"/g, '"'); +} diff --git a/extensions/image-preview/src/sizeStatusBarEntry.ts b/extensions/image-preview/src/sizeStatusBarEntry.ts new file mode 100644 index 0000000000..77a622c5ab --- /dev/null +++ b/extensions/image-preview/src/sizeStatusBarEntry.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { Disposable } from './dispose'; + +export class SizeStatusBarEntry extends Disposable { + private readonly _entry: vscode.StatusBarItem; + + constructor() { + super(); + this._entry = this._register(vscode.window.createStatusBarItem({ + id: 'imagePreview.size', + name: 'Image Size', + alignment: vscode.StatusBarAlignment.Right, + priority: 101 /* to the left of editor status (100) */, + })); + } + + public show() { + this._entry.show(); + } + + public hide() { + this._entry.hide(); + } + + public update(text: string) { + this._entry.text = text; + } +} diff --git a/extensions/image-preview/src/typings/ref.d.ts b/extensions/image-preview/src/typings/ref.d.ts new file mode 100644 index 0000000000..954bab971e --- /dev/null +++ b/extensions/image-preview/src/typings/ref.d.ts @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/// +/// +/// diff --git a/extensions/image-preview/src/zoomStatusBarEntry.ts b/extensions/image-preview/src/zoomStatusBarEntry.ts new file mode 100644 index 0000000000..5226bad9de --- /dev/null +++ b/extensions/image-preview/src/zoomStatusBarEntry.ts @@ -0,0 +1,68 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import * as nls from 'vscode-nls'; +import { Disposable } from './dispose'; + +const localize = nls.loadMessageBundle(); + +const selectZoomLevelCommandId = '_imagePreview.selectZoomLevel'; + +type Scale = number | 'fit'; + +export class ZoomStatusBarEntry extends Disposable { + private readonly _entry: vscode.StatusBarItem; + + private readonly _onDidChangeScale = this._register(new vscode.EventEmitter<{ scale: Scale }>()); + public readonly onDidChangeScale = this._onDidChangeScale.event; + + constructor() { + super(); + this._entry = this._register(vscode.window.createStatusBarItem({ + id: 'imagePreview.zoom', + name: 'Image Zoom', + alignment: vscode.StatusBarAlignment.Right, + priority: 102 /* to the left of editor size entry (101) */, + })); + + this._register(vscode.commands.registerCommand(selectZoomLevelCommandId, async () => { + type MyPickItem = vscode.QuickPickItem & { scale: Scale }; + + const scales: Scale[] = [10, 5, 2, 1, 0.5, 0.2, 'fit']; + const options = scales.map((scale): MyPickItem => ({ + label: this.zoomLabel(scale), + scale + })); + + const pick = await vscode.window.showQuickPick(options, { + placeHolder: localize('zoomStatusBar.placeholder', "Select zoom level") + }); + if (pick) { + this._onDidChangeScale.fire({ scale: pick.scale }); + } + })); + + this._entry.command = selectZoomLevelCommandId; + } + + public show() { + this._entry.show(); + } + + public hide() { + this._entry.hide(); + } + + public update(scale: Scale) { + this._entry.text = this.zoomLabel(scale); + } + + private zoomLabel(scale: Scale): string { + return scale === 'fit' + ? localize('zoomStatusBar.wholeImageLabel', "Whole Image") + : `${Math.round(scale * 100)}%`; + } +} diff --git a/extensions/image-preview/tsconfig.json b/extensions/image-preview/tsconfig.json new file mode 100644 index 0000000000..d0797affba --- /dev/null +++ b/extensions/image-preview/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../shared.tsconfig.json", + "compilerOptions": { + "outDir": "./out", + "experimentalDecorators": true + }, + "include": [ + "src/**/*" + ] +} diff --git a/extensions/image-preview/yarn.lock b/extensions/image-preview/yarn.lock new file mode 100644 index 0000000000..e79cafaa0b --- /dev/null +++ b/extensions/image-preview/yarn.lock @@ -0,0 +1,46 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +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" + zone.js "0.7.6" + +diagnostic-channel-publishers@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3" + integrity sha1-ji1geottef6IC1SLxYzGvrKIxPM= + +diagnostic-channel@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17" + integrity sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc= + dependencies: + semver "^5.3.0" + +semver@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== + +vscode-extension-telemetry@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.1.tgz#91387e06b33400c57abd48979b0e790415ae110b" + integrity sha512-TkKKG/B/J94DP5qf6xWB4YaqlhWDg6zbbqVx7Bz//stLQNnfE9XS1xm3f6fl24c5+bnEK0/wHgMgZYKIKxPeUA== + dependencies: + applicationinsights "1.0.8" + +vscode-nls@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" + integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== + +zone.js@0.7.6: + version "0.7.6" + resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009" + integrity sha1-+7w50+AmHQmG8boGMG6zrrDSIAk= diff --git a/extensions/import/src/services/config.json b/extensions/import/config.json similarity index 100% rename from extensions/import/src/services/config.json rename to extensions/import/config.json diff --git a/extensions/import/src/services/serviceClient.ts b/extensions/import/src/services/serviceClient.ts index 6fd2f09802..5ebdd8e085 100644 --- a/extensions/import/src/services/serviceClient.ts +++ b/extensions/import/src/services/serviceClient.ts @@ -18,8 +18,8 @@ import { Telemetry, LanguageClientErrorHandler } from './telemetry'; import * as Constants from '../constants'; import { TelemetryFeature, FlatFileImportFeature } from './features'; import * as serviceUtils from './serviceUtils'; - -const baseConfig = require('./config.json'); +import { promisify } from 'util'; +import { readFile } from 'fs'; export class ServiceClient { private statusView: vscode.StatusBarItem; @@ -28,8 +28,9 @@ export class ServiceClient { this.statusView = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); } - public startService(context: vscode.ExtensionContext): Promise { - let config: IConfig = JSON.parse(JSON.stringify(baseConfig)); + public async startService(context: vscode.ExtensionContext): Promise { + const rawConfig = await promisify(readFile)(path.join(context.extensionPath, 'config.json')); + const config = JSON.parse(rawConfig.toString()); config.installDirectory = path.join(context.extensionPath, config.installDirectory); config.proxy = vscode.workspace.getConfiguration('http').get('proxy'); config.strictSSL = vscode.workspace.getConfiguration('http').get('proxyStrictSSL') || true; @@ -163,4 +164,3 @@ class CustomOutputChannel implements vscode.OutputChannel { dispose(): void { } } - diff --git a/extensions/import/src/services/serviceUtils.ts b/extensions/import/src/services/serviceUtils.ts index 4ad647faa5..0dd9dad11f 100644 --- a/extensions/import/src/services/serviceUtils.ts +++ b/extensions/import/src/services/serviceUtils.ts @@ -6,8 +6,6 @@ import * as path from 'path'; import * as os from 'os'; -const baseConfig = require('./config.json'); - // The function is a duplicate of \src\paths.js. IT would be better to import path.js but it doesn't // work for now because the extension is running in different process. export function getAppDataPath(): string { @@ -55,25 +53,6 @@ export function verifyPlatform(): Thenable { } } -export function getServiceInstallConfig(basePath?: string): any { - if (!basePath) { - basePath = __dirname; - } - let config = JSON.parse(JSON.stringify(baseConfig)); - config.installDirectory = path.join(basePath, config.installDirectory); - - return config; -} - -export function getResolvedServiceInstallationPath(runtime: Runtime, basePath?: string): string { - let config = getServiceInstallConfig(basePath); - let dir = config.installDirectory; - dir = dir.replace('{#version#}', config.version); - dir = dir.replace('{#platform#}', getRuntimeDisplayName(runtime)); - - return dir; -} - export function getRuntimeDisplayName(runtime: Runtime): string { switch (runtime) { case Runtime.Windows_64: diff --git a/extensions/import/src/wizard/pages/modifyColumnsPage.ts b/extensions/import/src/wizard/pages/modifyColumnsPage.ts index b2ea8f23ba..d31c509e41 100644 --- a/extensions/import/src/wizard/pages/modifyColumnsPage.ts +++ b/extensions/import/src/wizard/pages/modifyColumnsPage.ts @@ -95,9 +95,9 @@ export class ModifyColumnsPage extends ImportPage { title: '' } ], { - horizontal: false, - componentWidth: '100%' - }).component(); + horizontal: false, + componentWidth: '100%' + }).component(); this.loading.component = this.form; await this.view.initializeModel(this.form); diff --git a/extensions/integration-tests/package.json b/extensions/integration-tests/package.json index 8608b31f73..91eed9bcc3 100644 --- a/extensions/integration-tests/package.json +++ b/extensions/integration-tests/package.json @@ -50,7 +50,7 @@ }, "devDependencies": { "@types/chai": "3.4.34", - "@types/node": "7.0.43", + "@types/node": "^10.14.8", "adstest": "github:ranasaria/adstest.git#0.0.2", "chai": "3.5.0", "mocha-junit-reporter": "^1.17.0", diff --git a/extensions/integration-tests/yarn.lock b/extensions/integration-tests/yarn.lock index 90c5dd6646..f1af198360 100644 --- a/extensions/integration-tests/yarn.lock +++ b/extensions/integration-tests/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-3.4.34.tgz#d5335792823bb09cddd5e38c3d211b709183854d" integrity sha1-1TNXkoI7sJzd1eOMPSEbcJGDhU0= -"@types/node@7.0.43": - version "7.0.43" - resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c" - integrity sha512-7scYwwfHNppXvH/9JzakbVxk0o0QUILVk1Lv64GRaxwPuGpnF1QBiwdvhDpLcymb8BpomQL3KYoWKq3wUdDMhQ== +"@types/node@^10.14.8": + version "10.14.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.17.tgz#b96d4dd3e427382482848948041d3754d40fd5ce" + integrity sha512-p/sGgiPaathCfOtqu2fx5Mu1bcjuP8ALFg4xpGgNkcin7LwRyzUKniEHBKdcE1RPsenq5JVPIpMTJSygLboygQ== "@types/node@^8.0.47": version "8.10.45" diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index bf76da32db..6d99b5f84a 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -14,7 +14,7 @@ "dependencies": { "jsonc-parser": "^2.1.1", "request-light": "^0.2.4", - "vscode-json-languageservice": "^3.3.1", + "vscode-json-languageservice": "^3.3.3", "vscode-languageserver": "^5.3.0-next.8", "vscode-nls": "^4.1.1", "vscode-uri": "^2.0.3" diff --git a/extensions/json-language-features/server/src/jsonServerMain.ts b/extensions/json-language-features/server/src/jsonServerMain.ts index 013ed5e2a6..52d6579e01 100644 --- a/extensions/json-language-features/server/src/jsonServerMain.ts +++ b/extensions/json-language-features/server/src/jsonServerMain.ts @@ -312,7 +312,7 @@ function validateTextDocument(textDocument: TextDocument, callback?: (diagnostic const jsonDocument = getJSONDocument(textDocument); const version = textDocument.version; - const documentSettings: DocumentLanguageSettings = textDocument.languageId === 'jsonc' ? { comments: 'ignore', trailingCommas: 'ignore' } : { comments: 'error', trailingCommas: 'error' }; + const documentSettings: DocumentLanguageSettings = textDocument.languageId === 'jsonc' ? { comments: 'ignore', trailingCommas: 'warning' } : { comments: 'error', trailingCommas: 'error' }; languageService.doValidation(textDocument, jsonDocument, documentSettings).then(diagnostics => { setTimeout(() => { const currDocument = documents.get(textDocument.uri); diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 3c176e1260..12e39de96a 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -54,11 +54,6 @@ https-proxy-agent@^2.2.1: agent-base "^4.1.0" debug "^3.1.0" -jsonc-parser@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.1.0.tgz#eb0d0c7a3c33048524ce3574c57c7278fb2f1bf3" - integrity sha512-n9GrT8rrr2fhvBbANa1g+xFmgGK5X91KFeDwlKQ3+SJfmH5+tKv/M/kahx/TXOMflfWHKGKqKyfHQaLKTNzJ6w== - jsonc-parser@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.1.1.tgz#83dc3d7a6e7186346b889b1280eefa04446c6d3e" @@ -78,12 +73,12 @@ request-light@^0.2.4: https-proxy-agent "^2.2.1" vscode-nls "^4.0.0" -vscode-json-languageservice@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.3.1.tgz#4ad2c82db849a7bbe54fcbf5c9b3a2ed26dc8fee" - integrity sha512-Qyvlrftexu1acvwbMt+CDehVrDZtFV1GAJrKdOCHQL9bWNhzI06KEiSd4iXR0NUOuAdroG/uU4wBkH6e5CcTXg== +vscode-json-languageservice@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.3.3.tgz#f7e512a2cd5e82fecbebf507d6fceaea47661297" + integrity sha512-5vL3OXTUuQpn6+tGd47dopio+7WwbtIZ07zfYMzAUX8eVWPZjfEsLeSWmQk5Xw+vwgu+j5zC4koz5UofLDGGRA== dependencies: - jsonc-parser "^2.1.0" + jsonc-parser "^2.1.1" vscode-languageserver-types "^3.15.0-next.2" vscode-nls "^4.1.1" vscode-uri "^2.0.3" diff --git a/extensions/json/package.json b/extensions/json/package.json index e23e86b14a..6ef4b97169 100644 --- a/extensions/json/package.json +++ b/extensions/json/package.json @@ -50,8 +50,7 @@ ".babelrc", ".jsonc", ".eslintrc", - ".eslintrc.json", - "tslint.json" + ".eslintrc.json" ], "configuration": "./language-configuration.json" } diff --git a/extensions/markdown-basics/syntaxes/markdown.tmLanguage.json b/extensions/markdown-basics/syntaxes/markdown.tmLanguage.json index 3fe94d8cf7..61b975b701 100644 --- a/extensions/markdown-basics/syntaxes/markdown.tmLanguage.json +++ b/extensions/markdown-basics/syntaxes/markdown.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/microsoft/vscode-markdown-tm-grammar/commit/eb3898715b50d7911377a650e383a768a3a21f25", + "version": "https://github.com/microsoft/vscode-markdown-tm-grammar/commit/00b05ebe6850083664d92d0eba6e5ee8f153baa6", "name": "Markdown", "scopeName": "text.html.markdown", "patterns": [ @@ -70,11 +70,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -103,11 +103,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -136,11 +136,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -169,11 +169,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -202,11 +202,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -235,11 +235,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -268,11 +268,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -294,18 +294,18 @@ ] }, "fenced_code_block_r": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(R|r|s|S|Rprofile)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(R|r|s|S|Rprofile|\\{\\.r.+?\\})(\\s+[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -334,11 +334,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -367,11 +367,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -403,11 +403,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -436,11 +436,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -469,11 +469,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -502,11 +502,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -535,11 +535,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -568,11 +568,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -601,11 +601,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -634,11 +634,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -667,11 +667,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -700,11 +700,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -716,7 +716,7 @@ { "begin": "(^|\\G)(\\s*)(.*)", "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", - "contentName": "meta.embedded.block.cpp", + "contentName": "meta.embedded.block.cpp source.cpp", "patterns": [ { "include": "source.cpp" @@ -733,11 +733,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -766,11 +766,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -799,11 +799,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -832,11 +832,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -865,11 +865,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -898,11 +898,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -931,11 +931,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -957,18 +957,18 @@ ] }, "fenced_code_block_js": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(js|jsx|javascript|es6|mjs)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(js|jsx|javascript|es6|mjs|\\{\\.js.+?\\})(\\s+[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -997,11 +997,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1030,11 +1030,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1063,11 +1063,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1096,11 +1096,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1129,11 +1129,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1162,11 +1162,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1195,11 +1195,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1228,11 +1228,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1261,11 +1261,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1287,18 +1287,18 @@ ] }, "fenced_code_block_python": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(python|py|py3|rpy|pyw|cpy|SConstruct|Sconstruct|sconstruct|SConscript|gyp|gypi)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(python|py|py3|rpy|pyw|cpy|SConstruct|Sconstruct|sconstruct|SConscript|gyp|gypi|\\{\\.python.+?\\})(\\s+[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1327,11 +1327,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1353,18 +1353,18 @@ ] }, "fenced_code_block_rust": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(rust|rs)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(rust|rs|\\{\\.rust.+?\\})(\\s+[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1393,11 +1393,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1419,18 +1419,18 @@ ] }, "fenced_code_block_shell": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(shell|sh|bash|zsh|bashrc|bash_profile|bash_login|profile|bash_logout|.textmate_init)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(shell|sh|bash|zsh|bashrc|bash_profile|bash_login|profile|bash_logout|.textmate_init|\\{\\.bash.+?\\})(\\s+[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1459,11 +1459,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1492,11 +1492,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1525,11 +1525,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1558,11 +1558,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1591,11 +1591,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1624,11 +1624,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { @@ -1657,11 +1657,11 @@ "3": { "name": "punctuation.definition.markdown" }, - "5": { - "name": "fenced_code.block.language" + "4": { + "name": "fenced_code.block.language.markdown" }, - "6": { - "name": "fenced_code.block.language.attributes" + "5": { + "name": "fenced_code.block.language.attributes.markdown" } }, "endCaptures": { diff --git a/extensions/markdown-language-features/media/index.js b/extensions/markdown-language-features/media/index.js index 31b478d7eb..22d5028abf 100644 --- a/extensions/markdown-language-features/media/index.js +++ b/extensions/markdown-language-features/media/index.js @@ -1005,4 +1005,4 @@ exports.getSettings = getSettings; /***/ }) /******/ }); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2xvZGFzaC50aHJvdHRsZS9pbmRleC5qcyIsIndlYnBhY2s6Ly8vKHdlYnBhY2spL2J1aWxkaW4vZ2xvYmFsLmpzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2FjdGl2ZUxpbmVNYXJrZXIudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvZXZlbnRzLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2luZGV4LnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL21lc3NhZ2luZy50cyIsIndlYnBhY2s6Ly8vLi9wcmV2aWV3LXNyYy9zY3JvbGwtc3luYy50cyIsIndlYnBhY2s6Ly8vLi9wcmV2aWV3LXNyYy9zZXR0aW5ncy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQSx5REFBaUQsY0FBYztBQUMvRDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBMkIsMEJBQTBCLEVBQUU7QUFDdkQseUNBQWlDLGVBQWU7QUFDaEQ7QUFDQTtBQUNBOztBQUVBO0FBQ0EsOERBQXNELCtEQUErRDs7QUFFckg7QUFDQTs7O0FBR0E7QUFDQTs7Ozs7Ozs7Ozs7O0FDbkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFNBQVM7QUFDcEIsV0FBVyxPQUFPO0FBQ2xCLFdBQVcsT0FBTyxZQUFZO0FBQzlCLFdBQVcsUUFBUTtBQUNuQjtBQUNBLFdBQVcsT0FBTztBQUNsQjtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLDhDQUE4QyxrQkFBa0I7QUFDaEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFNBQVM7QUFDcEIsV0FBVyxPQUFPO0FBQ2xCLFdBQVcsT0FBTyxZQUFZO0FBQzlCLFdBQVcsUUFBUTtBQUNuQjtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtREFBbUQsb0JBQW9CO0FBQ3ZFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLEVBQUU7QUFDYixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsRUFBRTtBQUNiLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0Esb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLEVBQUU7QUFDYixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxFQUFFO0FBQ2IsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOzs7Ozs7Ozs7Ozs7O0FDdGJBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsNENBQTRDOztBQUU1Qzs7Ozs7Ozs7Ozs7Ozs7O0FDbkJBOzs7Z0dBR2dHO0FBQ2hHLCtGQUF5RDtBQUV6RCxNQUFhLGdCQUFnQjtJQUc1Qiw4QkFBOEIsQ0FBQyxJQUFZO1FBQzFDLE1BQU0sRUFBRSxRQUFRLEVBQUUsR0FBRyxzQ0FBd0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwRCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsSUFBSSxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDNUMsQ0FBQztJQUVELE9BQU8sQ0FBQyxNQUErQjtRQUN0QyxJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3pDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNoQyxJQUFJLENBQUMsUUFBUSxHQUFHLE1BQU0sQ0FBQztJQUN4QixDQUFDO0lBRUQsb0JBQW9CLENBQUMsT0FBZ0M7UUFDcEQsSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUNiLE9BQU87U0FDUDtRQUNELE9BQU8sQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsdUJBQXVCLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDNUUsQ0FBQztJQUVELGtCQUFrQixDQUFDLE9BQWdDO1FBQ2xELElBQUksQ0FBQyxPQUFPLEVBQUU7WUFDYixPQUFPO1NBQ1A7UUFDRCxPQUFPLENBQUMsU0FBUyxJQUFJLG1CQUFtQixDQUFDO0lBQzFDLENBQUM7Q0FDRDtBQTNCRCw0Q0EyQkM7Ozs7Ozs7Ozs7Ozs7O0FDakNEOzs7Z0dBR2dHOztBQUVoRyxTQUFnQixrQkFBa0IsQ0FBQyxDQUFhO0lBQy9DLElBQUksUUFBUSxDQUFDLFVBQVUsS0FBSyxTQUFTLElBQUksUUFBUSxDQUFDLFVBQW9CLEtBQUssZUFBZSxFQUFFO1FBQzNGLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxrQkFBa0IsRUFBRSxDQUFDLENBQUMsQ0FBQztLQUNqRDtTQUFNO1FBQ04sQ0FBQyxFQUFFLENBQUM7S0FDSjtBQUNGLENBQUM7QUFORCxnREFNQzs7Ozs7Ozs7Ozs7Ozs7QUNYRDs7O2dHQUdnRzs7QUFFaEcsOEdBQXNEO0FBQ3RELGdGQUE4QztBQUM5Qyx5RkFBb0Q7QUFDcEQsK0ZBQXNIO0FBQ3RILHNGQUFrRDtBQUNsRCx1R0FBNkM7QUFJN0MsSUFBSSxjQUFjLEdBQUcsSUFBSSxDQUFDO0FBQzFCLE1BQU0sTUFBTSxHQUFHLElBQUksbUNBQWdCLEVBQUUsQ0FBQztBQUN0QyxNQUFNLFFBQVEsR0FBRyxzQkFBVyxFQUFFLENBQUM7QUFFL0IsTUFBTSxNQUFNLEdBQUcsZ0JBQWdCLEVBQUUsQ0FBQztBQUVsQyxvQkFBb0I7QUFDcEIsSUFBSSxLQUFLLEdBQUcsa0JBQU8sQ0FBc0MsWUFBWSxDQUFDLENBQUM7QUFDdkUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUV2QixNQUFNLFNBQVMsR0FBRyxpQ0FBcUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUVoRCxNQUFNLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUN2QyxNQUFNLENBQUMsbUJBQW1CLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBRWhELE1BQU0sQ0FBQyxNQUFNLEdBQUcsR0FBRyxFQUFFO0lBQ3BCLGdCQUFnQixFQUFFLENBQUM7QUFDcEIsQ0FBQyxDQUFDO0FBRUYsMkJBQWtCLENBQUMsR0FBRyxFQUFFO0lBQ3ZCLElBQUksUUFBUSxDQUFDLHVCQUF1QixFQUFFO1FBQ3JDLFVBQVUsQ0FBQyxHQUFHLEVBQUU7WUFDZix5Q0FBeUM7WUFDekMsSUFBSSxLQUFLLENBQUMsUUFBUSxFQUFFO2dCQUNuQixNQUFNLE9BQU8sR0FBRyx1Q0FBeUIsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQzFELElBQUksT0FBTyxFQUFFO29CQUNaLGNBQWMsR0FBRyxJQUFJLENBQUM7b0JBQ3RCLHNDQUF3QixDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztpQkFDdkM7YUFDRDtpQkFBTTtnQkFDTixNQUFNLFdBQVcsR0FBRyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7Z0JBQ25DLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUU7b0JBQ3hCLGNBQWMsR0FBRyxJQUFJLENBQUM7b0JBQ3RCLHNDQUF3QixDQUFDLFdBQVcsQ0FBQyxDQUFDO2lCQUN0QzthQUNEO1FBQ0YsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0tBQ047QUFDRixDQUFDLENBQUMsQ0FBQztBQUVILE1BQU0sWUFBWSxHQUFHLENBQUMsR0FBRyxFQUFFO0lBQzFCLE1BQU0sUUFBUSxHQUFHLFFBQVEsQ0FBQyxDQUFDLElBQVksRUFBRSxFQUFFO1FBQzFDLGNBQWMsR0FBRyxJQUFJLENBQUM7UUFDdEIsc0NBQXdCLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDaEMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBRVAsT0FBTyxDQUFDLElBQVksRUFBRSxRQUFhLEVBQUUsRUFBRTtRQUN0QyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQ2pCLFFBQVEsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1lBQ3JCLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUNmO0lBQ0YsQ0FBQyxDQUFDO0FBQ0gsQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUVMLElBQUksZ0JBQWdCLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRTtJQUNwQyxNQUFNLFNBQVMsR0FBb0QsRUFBRSxDQUFDO0lBQ3RFLElBQUksTUFBTSxHQUFHLFFBQVEsQ0FBQyxvQkFBb0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNsRCxJQUFJLE1BQU0sRUFBRTtRQUNYLElBQUksQ0FBQyxDQUFDO1FBQ04sS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ25DLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUV0QixJQUFJLEdBQUcsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxFQUFFO2dCQUN0QyxHQUFHLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQzthQUNoQztZQUVELFNBQVMsQ0FBQyxJQUFJLENBQUM7Z0JBQ2QsRUFBRSxFQUFFLEdBQUcsQ0FBQyxFQUFFO2dCQUNWLE1BQU0sRUFBRSxHQUFHLENBQUMsTUFBTTtnQkFDbEIsS0FBSyxFQUFFLEdBQUcsQ0FBQyxLQUFLO2FBQ2hCLENBQUMsQ0FBQztTQUNIO1FBRUQsU0FBUyxDQUFDLFdBQVcsQ0FBQyxpQkFBaUIsRUFBRSxTQUFTLENBQUMsQ0FBQztLQUNwRDtBQUNGLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztBQUVQLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsR0FBRyxFQUFFO0lBQ3RDLGNBQWMsR0FBRyxJQUFJLENBQUM7SUFDdEIsZ0JBQWdCLEVBQUUsQ0FBQztBQUNwQixDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7QUFFVCxNQUFNLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxFQUFFO0lBQzFDLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEtBQUssUUFBUSxDQUFDLE1BQU0sRUFBRTtRQUMxQyxPQUFPO0tBQ1A7SUFFRCxRQUFRLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFO1FBQ3hCLEtBQUssZ0NBQWdDO1lBQ3BDLE1BQU0sQ0FBQyw4QkFBOEIsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3ZELE1BQU07UUFFUCxLQUFLLFlBQVk7WUFDaEIsWUFBWSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBQ3hDLE1BQU07S0FDUDtBQUNGLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztBQUVWLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLEVBQUU7SUFDN0MsSUFBSSxDQUFDLFFBQVEsQ0FBQywyQkFBMkIsRUFBRTtRQUMxQyxPQUFPO0tBQ1A7SUFFRCx5QkFBeUI7SUFDekIsS0FBSyxJQUFJLElBQUksR0FBRyxLQUFLLENBQUMsTUFBcUIsRUFBRSxJQUFJLEVBQUUsSUFBSSxHQUFHLElBQUksQ0FBQyxVQUF5QixFQUFFO1FBQ3pGLElBQUksSUFBSSxDQUFDLE9BQU8sS0FBSyxHQUFHLEVBQUU7WUFDekIsT0FBTztTQUNQO0tBQ0Q7SUFFRCxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO0lBQzNCLE1BQU0sSUFBSSxHQUFHLDhDQUFnQyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3RELElBQUksT0FBTyxJQUFJLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFO1FBQzdDLFNBQVMsQ0FBQyxXQUFXLENBQUMsVUFBVSxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0tBQzlEO0FBQ0YsQ0FBQyxDQUFDLENBQUM7QUFFSCxRQUFRLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxFQUFFO0lBQzFDLElBQUksQ0FBQyxLQUFLLEVBQUU7UUFDWCxPQUFPO0tBQ1A7SUFFRCxJQUFJLElBQUksR0FBUSxLQUFLLENBQUMsTUFBTSxDQUFDO0lBQzdCLE9BQU8sSUFBSSxFQUFFO1FBQ1osSUFBSSxJQUFJLENBQUMsT0FBTyxJQUFJLElBQUksQ0FBQyxPQUFPLEtBQUssR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUU7WUFDdEQsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRTtnQkFDOUMsTUFBTTthQUNOO1lBQ0QsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFO2dCQUN0SSxNQUFNLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLGdDQUFnQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxJQUFJLFlBQVksQ0FBQyxRQUFRLENBQUMsbUJBQW1CLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQ2xLLFNBQVMsQ0FBQyxXQUFXLENBQUMsV0FBVyxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7Z0JBQ3ZELEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDdkIsS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDO2dCQUN4QixNQUFNO2FBQ047WUFDRCxNQUFNO1NBQ047UUFDRCxJQUFJLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQztLQUN2QjtBQUNGLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztBQUVULElBQUksUUFBUSxDQUFDLHVCQUF1QixFQUFFO0lBQ3JDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLEdBQUcsRUFBRTtRQUMvQyxJQUFJLGNBQWMsRUFBRTtZQUNuQixjQUFjLEdBQUcsS0FBSyxDQUFDO1NBQ3ZCO2FBQU07WUFDTixNQUFNLElBQUksR0FBRyw4Q0FBZ0MsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDOUQsSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUU7Z0JBQzdDLFNBQVMsQ0FBQyxXQUFXLENBQUMsWUFBWSxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDOUMsS0FBSyxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7Z0JBQ2xCLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7YUFDdkI7U0FDRDtJQUNGLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0NBQ1I7QUFFRCxTQUFTLFlBQVksQ0FBQyxJQUFZO0lBQ2pDLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQywwQkFBMEIsRUFBRSxNQUFNLENBQUMsQ0FBQztBQUN6RCxDQUFDOzs7Ozs7Ozs7Ozs7OztBQzVLRDs7O2dHQUdnRzs7QUFFaEcsc0ZBQXlDO0FBUzVCLDZCQUFxQixHQUFHLENBQUMsTUFBVyxFQUFFLEVBQUU7SUFDcEQsT0FBTyxJQUFJO1FBQ1YsV0FBVyxDQUFDLElBQVksRUFBRSxJQUFZO1lBQ3JDLE1BQU0sQ0FBQyxXQUFXLENBQUM7Z0JBQ2xCLElBQUk7Z0JBQ0osTUFBTSxFQUFFLHNCQUFXLEVBQUUsQ0FBQyxNQUFNO2dCQUM1QixJQUFJO2FBQ0osQ0FBQyxDQUFDO1FBQ0osQ0FBQztLQUNELENBQUM7QUFDSCxDQUFDLENBQUM7Ozs7Ozs7Ozs7Ozs7O0FDeEJGOzs7Z0dBR2dHOztBQUVoRyxzRkFBeUM7QUFHekMsU0FBUyxLQUFLLENBQUMsR0FBVyxFQUFFLEdBQVcsRUFBRSxLQUFhO0lBQ3JELE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztBQUM1QyxDQUFDO0FBRUQsU0FBUyxTQUFTLENBQUMsSUFBWTtJQUM5QixPQUFPLEtBQUssQ0FBQyxDQUFDLEVBQUUsc0JBQVcsRUFBRSxDQUFDLFNBQVMsR0FBRyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7QUFDcEQsQ0FBQztBQVFELE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxHQUFHLEVBQUU7SUFDakMsSUFBSSxRQUEyQixDQUFDO0lBQ2hDLE9BQU8sR0FBRyxFQUFFO1FBQ1gsSUFBSSxDQUFDLFFBQVEsRUFBRTtZQUNkLFFBQVEsR0FBRyxDQUFDLEVBQUUsT0FBTyxFQUFFLFFBQVEsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDakQsS0FBSyxNQUFNLE9BQU8sSUFBSSxRQUFRLENBQUMsc0JBQXNCLENBQUMsV0FBVyxDQUFDLEVBQUU7Z0JBQ25FLE1BQU0sSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUUsQ0FBQztnQkFDakQsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRTtvQkFDakIsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sRUFBRSxPQUFzQixFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7aUJBQ3pEO2FBQ0Q7U0FDRDtRQUNELE9BQU8sUUFBUSxDQUFDO0lBQ2pCLENBQUMsQ0FBQztBQUNILENBQUMsQ0FBQyxFQUFFLENBQUM7QUFFTDs7Ozs7R0FLRztBQUNILFNBQWdCLHdCQUF3QixDQUFDLFVBQWtCO0lBQzFELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDMUMsTUFBTSxLQUFLLEdBQUcsbUJBQW1CLEVBQUUsQ0FBQztJQUNwQyxJQUFJLFFBQVEsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDO0lBQ2hDLEtBQUssTUFBTSxLQUFLLElBQUksS0FBSyxFQUFFO1FBQzFCLElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxVQUFVLEVBQUU7WUFDOUIsT0FBTyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxDQUFDO1NBQzVDO2FBQU0sSUFBSSxLQUFLLENBQUMsSUFBSSxHQUFHLFVBQVUsRUFBRTtZQUNuQyxPQUFPLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsQ0FBQztTQUNqQztRQUNELFFBQVEsR0FBRyxLQUFLLENBQUM7S0FDakI7SUFDRCxPQUFPLEVBQUUsUUFBUSxFQUFFLENBQUM7QUFDckIsQ0FBQztBQWJELDREQWFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQiwyQkFBMkIsQ0FBQyxNQUFjO0lBQ3pELE1BQU0sS0FBSyxHQUFHLG1CQUFtQixFQUFFLENBQUM7SUFDcEMsTUFBTSxRQUFRLEdBQUcsTUFBTSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUM7SUFDekMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDWixJQUFJLEVBQUUsR0FBRyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztJQUMxQixPQUFPLEVBQUUsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFO1FBQ25CLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDdEMsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1FBQzFELElBQUksTUFBTSxDQUFDLEdBQUcsR0FBRyxNQUFNLENBQUMsTUFBTSxJQUFJLFFBQVEsRUFBRTtZQUMzQyxFQUFFLEdBQUcsR0FBRyxDQUFDO1NBQ1Q7YUFDSTtZQUNKLEVBQUUsR0FBRyxHQUFHLENBQUM7U0FDVDtLQUNEO0lBQ0QsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzVCLE1BQU0sUUFBUSxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMscUJBQXFCLEVBQUUsQ0FBQztJQUMzRCxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksUUFBUSxDQUFDLEdBQUcsR0FBRyxRQUFRLEVBQUU7UUFDdkMsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzVCLE9BQU8sRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsQ0FBQztLQUNoRDtJQUNELE9BQU8sRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLENBQUM7QUFDaEMsQ0FBQztBQXRCRCxrRUFzQkM7QUFFRDs7R0FFRztBQUNILFNBQWdCLHdCQUF3QixDQUFDLElBQVk7SUFDcEQsSUFBSSxDQUFDLHNCQUFXLEVBQUUsQ0FBQyx1QkFBdUIsRUFBRTtRQUMzQyxPQUFPO0tBQ1A7SUFFRCxJQUFJLElBQUksSUFBSSxDQUFDLEVBQUU7UUFDZCxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDakMsT0FBTztLQUNQO0lBRUQsTUFBTSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsR0FBRyx3QkFBd0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMxRCxJQUFJLENBQUMsUUFBUSxFQUFFO1FBQ2QsT0FBTztLQUNQO0lBQ0QsSUFBSSxRQUFRLEdBQUcsQ0FBQyxDQUFDO0lBQ2pCLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMscUJBQXFCLEVBQUUsQ0FBQztJQUN0RCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDO0lBQzdCLElBQUksSUFBSSxJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUSxDQUFDLElBQUksRUFBRTtRQUN4Qyw4REFBOEQ7UUFDOUQsTUFBTSxlQUFlLEdBQUcsQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDN0UsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsRUFBRSxDQUFDLEdBQUcsR0FBRyxXQUFXLENBQUM7UUFDN0UsUUFBUSxHQUFHLFdBQVcsR0FBRyxlQUFlLEdBQUcsYUFBYSxDQUFDO0tBQ3pEO1NBQU07UUFDTixNQUFNLGlCQUFpQixHQUFHLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2xELFFBQVEsR0FBRyxXQUFXLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLGlCQUFpQixDQUFDLENBQUM7S0FDM0Q7SUFDRCxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLE9BQU8sR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDO0FBQ3ZFLENBQUM7QUEzQkQsNERBMkJDO0FBRUQsU0FBZ0IsZ0NBQWdDLENBQUMsTUFBYztJQUM5RCxNQUFNLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxHQUFHLDJCQUEyQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQy9ELElBQUksUUFBUSxFQUFFO1FBQ2IsTUFBTSxjQUFjLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1FBQ2hFLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDLE9BQU8sR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDMUUsSUFBSSxJQUFJLEVBQUU7WUFDVCxNQUFNLHVCQUF1QixHQUFHLGtCQUFrQixHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsRUFBRSxDQUFDLEdBQUcsR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDckgsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLElBQUksR0FBRyx1QkFBdUIsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ25GLE9BQU8sU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQ3ZCO2FBQ0k7WUFDSixNQUFNLHFCQUFxQixHQUFHLGtCQUFrQixHQUFHLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQzNFLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxJQUFJLEdBQUcscUJBQXFCLENBQUM7WUFDbkQsT0FBTyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDdkI7S0FDRDtJQUNELE9BQU8sSUFBSSxDQUFDO0FBQ2IsQ0FBQztBQWpCRCw0RUFpQkM7QUFFRDs7R0FFRztBQUNILFNBQWdCLHlCQUF5QixDQUFDLFFBQWdCO0lBQ3pELE9BQU8sbUJBQW1CLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtRQUM3QyxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxLQUFLLFFBQVEsQ0FBQztJQUN4QyxDQUFDLENBQUMsQ0FBQztBQUNKLENBQUM7QUFKRCw4REFJQzs7Ozs7Ozs7Ozs7Ozs7QUNoSkQ7OztnR0FHZ0c7O0FBYWhHLElBQUksY0FBYyxHQUFnQyxTQUFTLENBQUM7QUFFNUQsU0FBZ0IsT0FBTyxDQUFTLEdBQVc7SUFDMUMsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDLGNBQWMsQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO0lBQ3hFLElBQUksT0FBTyxFQUFFO1FBQ1osTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN2QyxJQUFJLElBQUksRUFBRTtZQUNULE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUN4QjtLQUNEO0lBRUQsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsR0FBRyxFQUFFLENBQUMsQ0FBQztBQUNuRCxDQUFDO0FBVkQsMEJBVUM7QUFFRCxTQUFnQixXQUFXO0lBQzFCLElBQUksY0FBYyxFQUFFO1FBQ25CLE9BQU8sY0FBYyxDQUFDO0tBQ3RCO0lBRUQsY0FBYyxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUMxQyxJQUFJLGNBQWMsRUFBRTtRQUNuQixPQUFPLGNBQWMsQ0FBQztLQUN0QjtJQUVELE1BQU0sSUFBSSxLQUFLLENBQUMseUJBQXlCLENBQUMsQ0FBQztBQUM1QyxDQUFDO0FBWEQsa0NBV0MiLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VzQ29udGVudCI6WyIgXHQvLyBUaGUgbW9kdWxlIGNhY2hlXG4gXHR2YXIgaW5zdGFsbGVkTW9kdWxlcyA9IHt9O1xuXG4gXHQvLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuIFx0ZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXG4gXHRcdC8vIENoZWNrIGlmIG1vZHVsZSBpcyBpbiBjYWNoZVxuIFx0XHRpZihpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSkge1xuIFx0XHRcdHJldHVybiBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXS5leHBvcnRzO1xuIFx0XHR9XG4gXHRcdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG4gXHRcdHZhciBtb2R1bGUgPSBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSA9IHtcbiBcdFx0XHRpOiBtb2R1bGVJZCxcbiBcdFx0XHRsOiBmYWxzZSxcbiBcdFx0XHRleHBvcnRzOiB7fVxuIFx0XHR9O1xuXG4gXHRcdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuIFx0XHRtb2R1bGVzW21vZHVsZUlkXS5jYWxsKG1vZHVsZS5leHBvcnRzLCBtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuIFx0XHQvLyBGbGFnIHRoZSBtb2R1bGUgYXMgbG9hZGVkXG4gXHRcdG1vZHVsZS5sID0gdHJ1ZTtcblxuIFx0XHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuIFx0XHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG4gXHR9XG5cblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGVzIG9iamVjdCAoX193ZWJwYWNrX21vZHVsZXNfXylcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubSA9IG1vZHVsZXM7XG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlIGNhY2hlXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmMgPSBpbnN0YWxsZWRNb2R1bGVzO1xuXG4gXHQvLyBkZWZpbmUgZ2V0dGVyIGZ1bmN0aW9uIGZvciBoYXJtb255IGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uZCA9IGZ1bmN0aW9uKGV4cG9ydHMsIG5hbWUsIGdldHRlcikge1xuIFx0XHRpZighX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIG5hbWUpKSB7XG4gXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIG5hbWUsIHtcbiBcdFx0XHRcdGNvbmZpZ3VyYWJsZTogZmFsc2UsXG4gXHRcdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxuIFx0XHRcdFx0Z2V0OiBnZXR0ZXJcbiBcdFx0XHR9KTtcbiBcdFx0fVxuIFx0fTtcblxuIFx0Ly8gZGVmaW5lIF9fZXNNb2R1bGUgb24gZXhwb3J0c1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5yID0gZnVuY3Rpb24oZXhwb3J0cykge1xuIFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgJ19fZXNNb2R1bGUnLCB7IHZhbHVlOiB0cnVlIH0pO1xuIFx0fTtcblxuIFx0Ly8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubiA9IGZ1bmN0aW9uKG1vZHVsZSkge1xuIFx0XHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cbiBcdFx0XHRmdW5jdGlvbiBnZXREZWZhdWx0KCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxuIFx0XHRcdGZ1bmN0aW9uIGdldE1vZHVsZUV4cG9ydHMoKSB7IHJldHVybiBtb2R1bGU7IH07XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18uZChnZXR0ZXIsICdhJywgZ2V0dGVyKTtcbiBcdFx0cmV0dXJuIGdldHRlcjtcbiBcdH07XG5cbiBcdC8vIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbFxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5vID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkgeyByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpOyB9O1xuXG4gXHQvLyBfX3dlYnBhY2tfcHVibGljX3BhdGhfX1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXCJcIjtcblxuXG4gXHQvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbiBcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IFwiLi9wcmV2aWV3LXNyYy9pbmRleC50c1wiKTtcbiIsIi8qKlxuICogbG9kYXNoIChDdXN0b20gQnVpbGQpIDxodHRwczovL2xvZGFzaC5jb20vPlxuICogQnVpbGQ6IGBsb2Rhc2ggbW9kdWxhcml6ZSBleHBvcnRzPVwibnBtXCIgLW8gLi9gXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9ycyA8aHR0cHM6Ly9qcXVlcnkub3JnLz5cbiAqIFJlbGVhc2VkIHVuZGVyIE1JVCBsaWNlbnNlIDxodHRwczovL2xvZGFzaC5jb20vbGljZW5zZT5cbiAqIEJhc2VkIG9uIFVuZGVyc2NvcmUuanMgMS44LjMgPGh0dHA6Ly91bmRlcnNjb3JlanMub3JnL0xJQ0VOU0U+XG4gKiBDb3B5cmlnaHQgSmVyZW15IEFzaGtlbmFzLCBEb2N1bWVudENsb3VkIGFuZCBJbnZlc3RpZ2F0aXZlIFJlcG9ydGVycyAmIEVkaXRvcnNcbiAqL1xuXG4vKiogVXNlZCBhcyB0aGUgYFR5cGVFcnJvcmAgbWVzc2FnZSBmb3IgXCJGdW5jdGlvbnNcIiBtZXRob2RzLiAqL1xudmFyIEZVTkNfRVJST1JfVEVYVCA9ICdFeHBlY3RlZCBhIGZ1bmN0aW9uJztcblxuLyoqIFVzZWQgYXMgcmVmZXJlbmNlcyBmb3IgdmFyaW91cyBgTnVtYmVyYCBjb25zdGFudHMuICovXG52YXIgTkFOID0gMCAvIDA7XG5cbi8qKiBgT2JqZWN0I3RvU3RyaW5nYCByZXN1bHQgcmVmZXJlbmNlcy4gKi9cbnZhciBzeW1ib2xUYWcgPSAnW29iamVjdCBTeW1ib2xdJztcblxuLyoqIFVzZWQgdG8gbWF0Y2ggbGVhZGluZyBhbmQgdHJhaWxpbmcgd2hpdGVzcGFjZS4gKi9cbnZhciByZVRyaW0gPSAvXlxccyt8XFxzKyQvZztcblxuLyoqIFVzZWQgdG8gZGV0ZWN0IGJhZCBzaWduZWQgaGV4YWRlY2ltYWwgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzQmFkSGV4ID0gL15bLStdMHhbMC05YS1mXSskL2k7XG5cbi8qKiBVc2VkIHRvIGRldGVjdCBiaW5hcnkgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzQmluYXJ5ID0gL14wYlswMV0rJC9pO1xuXG4vKiogVXNlZCB0byBkZXRlY3Qgb2N0YWwgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzT2N0YWwgPSAvXjBvWzAtN10rJC9pO1xuXG4vKiogQnVpbHQtaW4gbWV0aG9kIHJlZmVyZW5jZXMgd2l0aG91dCBhIGRlcGVuZGVuY3kgb24gYHJvb3RgLiAqL1xudmFyIGZyZWVQYXJzZUludCA9IHBhcnNlSW50O1xuXG4vKiogRGV0ZWN0IGZyZWUgdmFyaWFibGUgYGdsb2JhbGAgZnJvbSBOb2RlLmpzLiAqL1xudmFyIGZyZWVHbG9iYWwgPSB0eXBlb2YgZ2xvYmFsID09ICdvYmplY3QnICYmIGdsb2JhbCAmJiBnbG9iYWwuT2JqZWN0ID09PSBPYmplY3QgJiYgZ2xvYmFsO1xuXG4vKiogRGV0ZWN0IGZyZWUgdmFyaWFibGUgYHNlbGZgLiAqL1xudmFyIGZyZWVTZWxmID0gdHlwZW9mIHNlbGYgPT0gJ29iamVjdCcgJiYgc2VsZiAmJiBzZWxmLk9iamVjdCA9PT0gT2JqZWN0ICYmIHNlbGY7XG5cbi8qKiBVc2VkIGFzIGEgcmVmZXJlbmNlIHRvIHRoZSBnbG9iYWwgb2JqZWN0LiAqL1xudmFyIHJvb3QgPSBmcmVlR2xvYmFsIHx8IGZyZWVTZWxmIHx8IEZ1bmN0aW9uKCdyZXR1cm4gdGhpcycpKCk7XG5cbi8qKiBVc2VkIGZvciBidWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcy4gKi9cbnZhciBvYmplY3RQcm90byA9IE9iamVjdC5wcm90b3R5cGU7XG5cbi8qKlxuICogVXNlZCB0byByZXNvbHZlIHRoZVxuICogW2B0b1N0cmluZ1RhZ2BdKGh0dHA6Ly9lY21hLWludGVybmF0aW9uYWwub3JnL2VjbWEtMjYyLzcuMC8jc2VjLW9iamVjdC5wcm90b3R5cGUudG9zdHJpbmcpXG4gKiBvZiB2YWx1ZXMuXG4gKi9cbnZhciBvYmplY3RUb1N0cmluZyA9IG9iamVjdFByb3RvLnRvU3RyaW5nO1xuXG4vKiBCdWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcyBmb3IgdGhvc2Ugd2l0aCB0aGUgc2FtZSBuYW1lIGFzIG90aGVyIGBsb2Rhc2hgIG1ldGhvZHMuICovXG52YXIgbmF0aXZlTWF4ID0gTWF0aC5tYXgsXG4gICAgbmF0aXZlTWluID0gTWF0aC5taW47XG5cbi8qKlxuICogR2V0cyB0aGUgdGltZXN0YW1wIG9mIHRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRoYXQgaGF2ZSBlbGFwc2VkIHNpbmNlXG4gKiB0aGUgVW5peCBlcG9jaCAoMSBKYW51YXJ5IDE5NzAgMDA6MDA6MDAgVVRDKS5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDIuNC4wXG4gKiBAY2F0ZWdvcnkgRGF0ZVxuICogQHJldHVybnMge251bWJlcn0gUmV0dXJucyB0aGUgdGltZXN0YW1wLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmRlZmVyKGZ1bmN0aW9uKHN0YW1wKSB7XG4gKiAgIGNvbnNvbGUubG9nKF8ubm93KCkgLSBzdGFtcCk7XG4gKiB9LCBfLm5vdygpKTtcbiAqIC8vID0+IExvZ3MgdGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgaXQgdG9vayBmb3IgdGhlIGRlZmVycmVkIGludm9jYXRpb24uXG4gKi9cbnZhciBub3cgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIHJvb3QuRGF0ZS5ub3coKTtcbn07XG5cbi8qKlxuICogQ3JlYXRlcyBhIGRlYm91bmNlZCBmdW5jdGlvbiB0aGF0IGRlbGF5cyBpbnZva2luZyBgZnVuY2AgdW50aWwgYWZ0ZXIgYHdhaXRgXG4gKiBtaWxsaXNlY29uZHMgaGF2ZSBlbGFwc2VkIHNpbmNlIHRoZSBsYXN0IHRpbWUgdGhlIGRlYm91bmNlZCBmdW5jdGlvbiB3YXNcbiAqIGludm9rZWQuIFRoZSBkZWJvdW5jZWQgZnVuY3Rpb24gY29tZXMgd2l0aCBhIGBjYW5jZWxgIG1ldGhvZCB0byBjYW5jZWxcbiAqIGRlbGF5ZWQgYGZ1bmNgIGludm9jYXRpb25zIGFuZCBhIGBmbHVzaGAgbWV0aG9kIHRvIGltbWVkaWF0ZWx5IGludm9rZSB0aGVtLlxuICogUHJvdmlkZSBgb3B0aW9uc2AgdG8gaW5kaWNhdGUgd2hldGhlciBgZnVuY2Agc2hvdWxkIGJlIGludm9rZWQgb24gdGhlXG4gKiBsZWFkaW5nIGFuZC9vciB0cmFpbGluZyBlZGdlIG9mIHRoZSBgd2FpdGAgdGltZW91dC4gVGhlIGBmdW5jYCBpcyBpbnZva2VkXG4gKiB3aXRoIHRoZSBsYXN0IGFyZ3VtZW50cyBwcm92aWRlZCB0byB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uLiBTdWJzZXF1ZW50XG4gKiBjYWxscyB0byB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uIHJldHVybiB0aGUgcmVzdWx0IG9mIHRoZSBsYXN0IGBmdW5jYFxuICogaW52b2NhdGlvbi5cbiAqXG4gKiAqKk5vdGU6KiogSWYgYGxlYWRpbmdgIGFuZCBgdHJhaWxpbmdgIG9wdGlvbnMgYXJlIGB0cnVlYCwgYGZ1bmNgIGlzXG4gKiBpbnZva2VkIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0IG9ubHkgaWYgdGhlIGRlYm91bmNlZCBmdW5jdGlvblxuICogaXMgaW52b2tlZCBtb3JlIHRoYW4gb25jZSBkdXJpbmcgdGhlIGB3YWl0YCB0aW1lb3V0LlxuICpcbiAqIElmIGB3YWl0YCBpcyBgMGAgYW5kIGBsZWFkaW5nYCBpcyBgZmFsc2VgLCBgZnVuY2AgaW52b2NhdGlvbiBpcyBkZWZlcnJlZFxuICogdW50aWwgdG8gdGhlIG5leHQgdGljaywgc2ltaWxhciB0byBgc2V0VGltZW91dGAgd2l0aCBhIHRpbWVvdXQgb2YgYDBgLlxuICpcbiAqIFNlZSBbRGF2aWQgQ29yYmFjaG8ncyBhcnRpY2xlXShodHRwczovL2Nzcy10cmlja3MuY29tL2RlYm91bmNpbmctdGhyb3R0bGluZy1leHBsYWluZWQtZXhhbXBsZXMvKVxuICogZm9yIGRldGFpbHMgb3ZlciB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBgXy5kZWJvdW5jZWAgYW5kIGBfLnRocm90dGxlYC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDAuMS4wXG4gKiBAY2F0ZWdvcnkgRnVuY3Rpb25cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGRlYm91bmNlLlxuICogQHBhcmFtIHtudW1iZXJ9IFt3YWl0PTBdIFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIGRlbGF5LlxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zPXt9XSBUaGUgb3B0aW9ucyBvYmplY3QuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxlYWRpbmc9ZmFsc2VdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgbGVhZGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLm1heFdhaXRdXG4gKiAgVGhlIG1heGltdW0gdGltZSBgZnVuY2AgaXMgYWxsb3dlZCB0byBiZSBkZWxheWVkIGJlZm9yZSBpdCdzIGludm9rZWQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLnRyYWlsaW5nPXRydWVdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgdHJhaWxpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGRlYm91bmNlZCBmdW5jdGlvbi5cbiAqIEBleGFtcGxlXG4gKlxuICogLy8gQXZvaWQgY29zdGx5IGNhbGN1bGF0aW9ucyB3aGlsZSB0aGUgd2luZG93IHNpemUgaXMgaW4gZmx1eC5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdyZXNpemUnLCBfLmRlYm91bmNlKGNhbGN1bGF0ZUxheW91dCwgMTUwKSk7XG4gKlxuICogLy8gSW52b2tlIGBzZW5kTWFpbGAgd2hlbiBjbGlja2VkLCBkZWJvdW5jaW5nIHN1YnNlcXVlbnQgY2FsbHMuXG4gKiBqUXVlcnkoZWxlbWVudCkub24oJ2NsaWNrJywgXy5kZWJvdW5jZShzZW5kTWFpbCwgMzAwLCB7XG4gKiAgICdsZWFkaW5nJzogdHJ1ZSxcbiAqICAgJ3RyYWlsaW5nJzogZmFsc2VcbiAqIH0pKTtcbiAqXG4gKiAvLyBFbnN1cmUgYGJhdGNoTG9nYCBpcyBpbnZva2VkIG9uY2UgYWZ0ZXIgMSBzZWNvbmQgb2YgZGVib3VuY2VkIGNhbGxzLlxuICogdmFyIGRlYm91bmNlZCA9IF8uZGVib3VuY2UoYmF0Y2hMb2csIDI1MCwgeyAnbWF4V2FpdCc6IDEwMDAgfSk7XG4gKiB2YXIgc291cmNlID0gbmV3IEV2ZW50U291cmNlKCcvc3RyZWFtJyk7XG4gKiBqUXVlcnkoc291cmNlKS5vbignbWVzc2FnZScsIGRlYm91bmNlZCk7XG4gKlxuICogLy8gQ2FuY2VsIHRoZSB0cmFpbGluZyBkZWJvdW5jZWQgaW52b2NhdGlvbi5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdwb3BzdGF0ZScsIGRlYm91bmNlZC5jYW5jZWwpO1xuICovXG5mdW5jdGlvbiBkZWJvdW5jZShmdW5jLCB3YWl0LCBvcHRpb25zKSB7XG4gIHZhciBsYXN0QXJncyxcbiAgICAgIGxhc3RUaGlzLFxuICAgICAgbWF4V2FpdCxcbiAgICAgIHJlc3VsdCxcbiAgICAgIHRpbWVySWQsXG4gICAgICBsYXN0Q2FsbFRpbWUsXG4gICAgICBsYXN0SW52b2tlVGltZSA9IDAsXG4gICAgICBsZWFkaW5nID0gZmFsc2UsXG4gICAgICBtYXhpbmcgPSBmYWxzZSxcbiAgICAgIHRyYWlsaW5nID0gdHJ1ZTtcblxuICBpZiAodHlwZW9mIGZ1bmMgIT0gJ2Z1bmN0aW9uJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoRlVOQ19FUlJPUl9URVhUKTtcbiAgfVxuICB3YWl0ID0gdG9OdW1iZXIod2FpdCkgfHwgMDtcbiAgaWYgKGlzT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgbGVhZGluZyA9ICEhb3B0aW9ucy5sZWFkaW5nO1xuICAgIG1heGluZyA9ICdtYXhXYWl0JyBpbiBvcHRpb25zO1xuICAgIG1heFdhaXQgPSBtYXhpbmcgPyBuYXRpdmVNYXgodG9OdW1iZXIob3B0aW9ucy5tYXhXYWl0KSB8fCAwLCB3YWl0KSA6IG1heFdhaXQ7XG4gICAgdHJhaWxpbmcgPSAndHJhaWxpbmcnIGluIG9wdGlvbnMgPyAhIW9wdGlvbnMudHJhaWxpbmcgOiB0cmFpbGluZztcbiAgfVxuXG4gIGZ1bmN0aW9uIGludm9rZUZ1bmModGltZSkge1xuICAgIHZhciBhcmdzID0gbGFzdEFyZ3MsXG4gICAgICAgIHRoaXNBcmcgPSBsYXN0VGhpcztcblxuICAgIGxhc3RBcmdzID0gbGFzdFRoaXMgPSB1bmRlZmluZWQ7XG4gICAgbGFzdEludm9rZVRpbWUgPSB0aW1lO1xuICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkodGhpc0FyZywgYXJncyk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGxlYWRpbmdFZGdlKHRpbWUpIHtcbiAgICAvLyBSZXNldCBhbnkgYG1heFdhaXRgIHRpbWVyLlxuICAgIGxhc3RJbnZva2VUaW1lID0gdGltZTtcbiAgICAvLyBTdGFydCB0aGUgdGltZXIgZm9yIHRoZSB0cmFpbGluZyBlZGdlLlxuICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgd2FpdCk7XG4gICAgLy8gSW52b2tlIHRoZSBsZWFkaW5nIGVkZ2UuXG4gICAgcmV0dXJuIGxlYWRpbmcgPyBpbnZva2VGdW5jKHRpbWUpIDogcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gcmVtYWluaW5nV2FpdCh0aW1lKSB7XG4gICAgdmFyIHRpbWVTaW5jZUxhc3RDYWxsID0gdGltZSAtIGxhc3RDYWxsVGltZSxcbiAgICAgICAgdGltZVNpbmNlTGFzdEludm9rZSA9IHRpbWUgLSBsYXN0SW52b2tlVGltZSxcbiAgICAgICAgcmVzdWx0ID0gd2FpdCAtIHRpbWVTaW5jZUxhc3RDYWxsO1xuXG4gICAgcmV0dXJuIG1heGluZyA/IG5hdGl2ZU1pbihyZXN1bHQsIG1heFdhaXQgLSB0aW1lU2luY2VMYXN0SW52b2tlKSA6IHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIHNob3VsZEludm9rZSh0aW1lKSB7XG4gICAgdmFyIHRpbWVTaW5jZUxhc3RDYWxsID0gdGltZSAtIGxhc3RDYWxsVGltZSxcbiAgICAgICAgdGltZVNpbmNlTGFzdEludm9rZSA9IHRpbWUgLSBsYXN0SW52b2tlVGltZTtcblxuICAgIC8vIEVpdGhlciB0aGlzIGlzIHRoZSBmaXJzdCBjYWxsLCBhY3Rpdml0eSBoYXMgc3RvcHBlZCBhbmQgd2UncmUgYXQgdGhlXG4gICAgLy8gdHJhaWxpbmcgZWRnZSwgdGhlIHN5c3RlbSB0aW1lIGhhcyBnb25lIGJhY2t3YXJkcyBhbmQgd2UncmUgdHJlYXRpbmdcbiAgICAvLyBpdCBhcyB0aGUgdHJhaWxpbmcgZWRnZSwgb3Igd2UndmUgaGl0IHRoZSBgbWF4V2FpdGAgbGltaXQuXG4gICAgcmV0dXJuIChsYXN0Q2FsbFRpbWUgPT09IHVuZGVmaW5lZCB8fCAodGltZVNpbmNlTGFzdENhbGwgPj0gd2FpdCkgfHxcbiAgICAgICh0aW1lU2luY2VMYXN0Q2FsbCA8IDApIHx8IChtYXhpbmcgJiYgdGltZVNpbmNlTGFzdEludm9rZSA+PSBtYXhXYWl0KSk7XG4gIH1cblxuICBmdW5jdGlvbiB0aW1lckV4cGlyZWQoKSB7XG4gICAgdmFyIHRpbWUgPSBub3coKTtcbiAgICBpZiAoc2hvdWxkSW52b2tlKHRpbWUpKSB7XG4gICAgICByZXR1cm4gdHJhaWxpbmdFZGdlKHRpbWUpO1xuICAgIH1cbiAgICAvLyBSZXN0YXJ0IHRoZSB0aW1lci5cbiAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHJlbWFpbmluZ1dhaXQodGltZSkpO1xuICB9XG5cbiAgZnVuY3Rpb24gdHJhaWxpbmdFZGdlKHRpbWUpIHtcbiAgICB0aW1lcklkID0gdW5kZWZpbmVkO1xuXG4gICAgLy8gT25seSBpbnZva2UgaWYgd2UgaGF2ZSBgbGFzdEFyZ3NgIHdoaWNoIG1lYW5zIGBmdW5jYCBoYXMgYmVlblxuICAgIC8vIGRlYm91bmNlZCBhdCBsZWFzdCBvbmNlLlxuICAgIGlmICh0cmFpbGluZyAmJiBsYXN0QXJncykge1xuICAgICAgcmV0dXJuIGludm9rZUZ1bmModGltZSk7XG4gICAgfVxuICAgIGxhc3RBcmdzID0gbGFzdFRoaXMgPSB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGNhbmNlbCgpIHtcbiAgICBpZiAodGltZXJJZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjbGVhclRpbWVvdXQodGltZXJJZCk7XG4gICAgfVxuICAgIGxhc3RJbnZva2VUaW1lID0gMDtcbiAgICBsYXN0QXJncyA9IGxhc3RDYWxsVGltZSA9IGxhc3RUaGlzID0gdGltZXJJZCA9IHVuZGVmaW5lZDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGZsdXNoKCkge1xuICAgIHJldHVybiB0aW1lcklkID09PSB1bmRlZmluZWQgPyByZXN1bHQgOiB0cmFpbGluZ0VkZ2Uobm93KCkpO1xuICB9XG5cbiAgZnVuY3Rpb24gZGVib3VuY2VkKCkge1xuICAgIHZhciB0aW1lID0gbm93KCksXG4gICAgICAgIGlzSW52b2tpbmcgPSBzaG91bGRJbnZva2UodGltZSk7XG5cbiAgICBsYXN0QXJncyA9IGFyZ3VtZW50cztcbiAgICBsYXN0VGhpcyA9IHRoaXM7XG4gICAgbGFzdENhbGxUaW1lID0gdGltZTtcblxuICAgIGlmIChpc0ludm9raW5nKSB7XG4gICAgICBpZiAodGltZXJJZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBsZWFkaW5nRWRnZShsYXN0Q2FsbFRpbWUpO1xuICAgICAgfVxuICAgICAgaWYgKG1heGluZykge1xuICAgICAgICAvLyBIYW5kbGUgaW52b2NhdGlvbnMgaW4gYSB0aWdodCBsb29wLlxuICAgICAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHdhaXQpO1xuICAgICAgICByZXR1cm4gaW52b2tlRnVuYyhsYXN0Q2FsbFRpbWUpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAodGltZXJJZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHdhaXQpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG4gIGRlYm91bmNlZC5jYW5jZWwgPSBjYW5jZWw7XG4gIGRlYm91bmNlZC5mbHVzaCA9IGZsdXNoO1xuICByZXR1cm4gZGVib3VuY2VkO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSB0aHJvdHRsZWQgZnVuY3Rpb24gdGhhdCBvbmx5IGludm9rZXMgYGZ1bmNgIGF0IG1vc3Qgb25jZSBwZXJcbiAqIGV2ZXJ5IGB3YWl0YCBtaWxsaXNlY29uZHMuIFRoZSB0aHJvdHRsZWQgZnVuY3Rpb24gY29tZXMgd2l0aCBhIGBjYW5jZWxgXG4gKiBtZXRob2QgdG8gY2FuY2VsIGRlbGF5ZWQgYGZ1bmNgIGludm9jYXRpb25zIGFuZCBhIGBmbHVzaGAgbWV0aG9kIHRvXG4gKiBpbW1lZGlhdGVseSBpbnZva2UgdGhlbS4gUHJvdmlkZSBgb3B0aW9uc2AgdG8gaW5kaWNhdGUgd2hldGhlciBgZnVuY2BcbiAqIHNob3VsZCBiZSBpbnZva2VkIG9uIHRoZSBsZWFkaW5nIGFuZC9vciB0cmFpbGluZyBlZGdlIG9mIHRoZSBgd2FpdGBcbiAqIHRpbWVvdXQuIFRoZSBgZnVuY2AgaXMgaW52b2tlZCB3aXRoIHRoZSBsYXN0IGFyZ3VtZW50cyBwcm92aWRlZCB0byB0aGVcbiAqIHRocm90dGxlZCBmdW5jdGlvbi4gU3Vic2VxdWVudCBjYWxscyB0byB0aGUgdGhyb3R0bGVkIGZ1bmN0aW9uIHJldHVybiB0aGVcbiAqIHJlc3VsdCBvZiB0aGUgbGFzdCBgZnVuY2AgaW52b2NhdGlvbi5cbiAqXG4gKiAqKk5vdGU6KiogSWYgYGxlYWRpbmdgIGFuZCBgdHJhaWxpbmdgIG9wdGlvbnMgYXJlIGB0cnVlYCwgYGZ1bmNgIGlzXG4gKiBpbnZva2VkIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0IG9ubHkgaWYgdGhlIHRocm90dGxlZCBmdW5jdGlvblxuICogaXMgaW52b2tlZCBtb3JlIHRoYW4gb25jZSBkdXJpbmcgdGhlIGB3YWl0YCB0aW1lb3V0LlxuICpcbiAqIElmIGB3YWl0YCBpcyBgMGAgYW5kIGBsZWFkaW5nYCBpcyBgZmFsc2VgLCBgZnVuY2AgaW52b2NhdGlvbiBpcyBkZWZlcnJlZFxuICogdW50aWwgdG8gdGhlIG5leHQgdGljaywgc2ltaWxhciB0byBgc2V0VGltZW91dGAgd2l0aCBhIHRpbWVvdXQgb2YgYDBgLlxuICpcbiAqIFNlZSBbRGF2aWQgQ29yYmFjaG8ncyBhcnRpY2xlXShodHRwczovL2Nzcy10cmlja3MuY29tL2RlYm91bmNpbmctdGhyb3R0bGluZy1leHBsYWluZWQtZXhhbXBsZXMvKVxuICogZm9yIGRldGFpbHMgb3ZlciB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBgXy50aHJvdHRsZWAgYW5kIGBfLmRlYm91bmNlYC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDAuMS4wXG4gKiBAY2F0ZWdvcnkgRnVuY3Rpb25cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIHRocm90dGxlLlxuICogQHBhcmFtIHtudW1iZXJ9IFt3YWl0PTBdIFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHRocm90dGxlIGludm9jYXRpb25zIHRvLlxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zPXt9XSBUaGUgb3B0aW9ucyBvYmplY3QuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxlYWRpbmc9dHJ1ZV1cbiAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSBsZWFkaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLnRyYWlsaW5nPXRydWVdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgdHJhaWxpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IHRocm90dGxlZCBmdW5jdGlvbi5cbiAqIEBleGFtcGxlXG4gKlxuICogLy8gQXZvaWQgZXhjZXNzaXZlbHkgdXBkYXRpbmcgdGhlIHBvc2l0aW9uIHdoaWxlIHNjcm9sbGluZy5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdzY3JvbGwnLCBfLnRocm90dGxlKHVwZGF0ZVBvc2l0aW9uLCAxMDApKTtcbiAqXG4gKiAvLyBJbnZva2UgYHJlbmV3VG9rZW5gIHdoZW4gdGhlIGNsaWNrIGV2ZW50IGlzIGZpcmVkLCBidXQgbm90IG1vcmUgdGhhbiBvbmNlIGV2ZXJ5IDUgbWludXRlcy5cbiAqIHZhciB0aHJvdHRsZWQgPSBfLnRocm90dGxlKHJlbmV3VG9rZW4sIDMwMDAwMCwgeyAndHJhaWxpbmcnOiBmYWxzZSB9KTtcbiAqIGpRdWVyeShlbGVtZW50KS5vbignY2xpY2snLCB0aHJvdHRsZWQpO1xuICpcbiAqIC8vIENhbmNlbCB0aGUgdHJhaWxpbmcgdGhyb3R0bGVkIGludm9jYXRpb24uXG4gKiBqUXVlcnkod2luZG93KS5vbigncG9wc3RhdGUnLCB0aHJvdHRsZWQuY2FuY2VsKTtcbiAqL1xuZnVuY3Rpb24gdGhyb3R0bGUoZnVuYywgd2FpdCwgb3B0aW9ucykge1xuICB2YXIgbGVhZGluZyA9IHRydWUsXG4gICAgICB0cmFpbGluZyA9IHRydWU7XG5cbiAgaWYgKHR5cGVvZiBmdW5jICE9ICdmdW5jdGlvbicpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKEZVTkNfRVJST1JfVEVYVCk7XG4gIH1cbiAgaWYgKGlzT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgbGVhZGluZyA9ICdsZWFkaW5nJyBpbiBvcHRpb25zID8gISFvcHRpb25zLmxlYWRpbmcgOiBsZWFkaW5nO1xuICAgIHRyYWlsaW5nID0gJ3RyYWlsaW5nJyBpbiBvcHRpb25zID8gISFvcHRpb25zLnRyYWlsaW5nIDogdHJhaWxpbmc7XG4gIH1cbiAgcmV0dXJuIGRlYm91bmNlKGZ1bmMsIHdhaXQsIHtcbiAgICAnbGVhZGluZyc6IGxlYWRpbmcsXG4gICAgJ21heFdhaXQnOiB3YWl0LFxuICAgICd0cmFpbGluZyc6IHRyYWlsaW5nXG4gIH0pO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIHRoZVxuICogW2xhbmd1YWdlIHR5cGVdKGh0dHA6Ly93d3cuZWNtYS1pbnRlcm5hdGlvbmFsLm9yZy9lY21hLTI2Mi83LjAvI3NlYy1lY21hc2NyaXB0LWxhbmd1YWdlLXR5cGVzKVxuICogb2YgYE9iamVjdGAuIChlLmcuIGFycmF5cywgZnVuY3Rpb25zLCBvYmplY3RzLCByZWdleGVzLCBgbmV3IE51bWJlcigwKWAsIGFuZCBgbmV3IFN0cmluZygnJylgKVxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgMC4xLjBcbiAqIEBjYXRlZ29yeSBMYW5nXG4gKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiBgdmFsdWVgIGlzIGFuIG9iamVjdCwgZWxzZSBgZmFsc2VgLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmlzT2JqZWN0KHt9KTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0KFsxLCAyLCAzXSk7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc09iamVjdChfLm5vb3ApO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNPYmplY3QobnVsbCk7XG4gKiAvLyA9PiBmYWxzZVxuICovXG5mdW5jdGlvbiBpc09iamVjdCh2YWx1ZSkge1xuICB2YXIgdHlwZSA9IHR5cGVvZiB2YWx1ZTtcbiAgcmV0dXJuICEhdmFsdWUgJiYgKHR5cGUgPT0gJ29iamVjdCcgfHwgdHlwZSA9PSAnZnVuY3Rpb24nKTtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBvYmplY3QtbGlrZS4gQSB2YWx1ZSBpcyBvYmplY3QtbGlrZSBpZiBpdCdzIG5vdCBgbnVsbGBcbiAqIGFuZCBoYXMgYSBgdHlwZW9mYCByZXN1bHQgb2YgXCJvYmplY3RcIi5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDQuMC4wXG4gKiBAY2F0ZWdvcnkgTGFuZ1xuICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYHZhbHVlYCBpcyBvYmplY3QtbGlrZSwgZWxzZSBgZmFsc2VgLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZSh7fSk7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc09iamVjdExpa2UoWzEsIDIsIDNdKTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZShfLm5vb3ApO1xuICogLy8gPT4gZmFsc2VcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZShudWxsKTtcbiAqIC8vID0+IGZhbHNlXG4gKi9cbmZ1bmN0aW9uIGlzT2JqZWN0TGlrZSh2YWx1ZSkge1xuICByZXR1cm4gISF2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT0gJ29iamVjdCc7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgY2xhc3NpZmllZCBhcyBhIGBTeW1ib2xgIHByaW1pdGl2ZSBvciBvYmplY3QuXG4gKlxuICogQHN0YXRpY1xuICogQG1lbWJlck9mIF9cbiAqIEBzaW5jZSA0LjAuMFxuICogQGNhdGVnb3J5IExhbmdcbiAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGB2YWx1ZWAgaXMgYSBzeW1ib2wsIGVsc2UgYGZhbHNlYC5cbiAqIEBleGFtcGxlXG4gKlxuICogXy5pc1N5bWJvbChTeW1ib2wuaXRlcmF0b3IpO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNTeW1ib2woJ2FiYycpO1xuICogLy8gPT4gZmFsc2VcbiAqL1xuZnVuY3Rpb24gaXNTeW1ib2wodmFsdWUpIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PSAnc3ltYm9sJyB8fFxuICAgIChpc09iamVjdExpa2UodmFsdWUpICYmIG9iamVjdFRvU3RyaW5nLmNhbGwodmFsdWUpID09IHN5bWJvbFRhZyk7XG59XG5cbi8qKlxuICogQ29udmVydHMgYHZhbHVlYCB0byBhIG51bWJlci5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDQuMC4wXG4gKiBAY2F0ZWdvcnkgTGFuZ1xuICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gcHJvY2Vzcy5cbiAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgdGhlIG51bWJlci5cbiAqIEBleGFtcGxlXG4gKlxuICogXy50b051bWJlcigzLjIpO1xuICogLy8gPT4gMy4yXG4gKlxuICogXy50b051bWJlcihOdW1iZXIuTUlOX1ZBTFVFKTtcbiAqIC8vID0+IDVlLTMyNFxuICpcbiAqIF8udG9OdW1iZXIoSW5maW5pdHkpO1xuICogLy8gPT4gSW5maW5pdHlcbiAqXG4gKiBfLnRvTnVtYmVyKCczLjInKTtcbiAqIC8vID0+IDMuMlxuICovXG5mdW5jdGlvbiB0b051bWJlcih2YWx1ZSkge1xuICBpZiAodHlwZW9mIHZhbHVlID09ICdudW1iZXInKSB7XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9XG4gIGlmIChpc1N5bWJvbCh2YWx1ZSkpIHtcbiAgICByZXR1cm4gTkFOO1xuICB9XG4gIGlmIChpc09iamVjdCh2YWx1ZSkpIHtcbiAgICB2YXIgb3RoZXIgPSB0eXBlb2YgdmFsdWUudmFsdWVPZiA9PSAnZnVuY3Rpb24nID8gdmFsdWUudmFsdWVPZigpIDogdmFsdWU7XG4gICAgdmFsdWUgPSBpc09iamVjdChvdGhlcikgPyAob3RoZXIgKyAnJykgOiBvdGhlcjtcbiAgfVxuICBpZiAodHlwZW9mIHZhbHVlICE9ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIHZhbHVlID09PSAwID8gdmFsdWUgOiArdmFsdWU7XG4gIH1cbiAgdmFsdWUgPSB2YWx1ZS5yZXBsYWNlKHJlVHJpbSwgJycpO1xuICB2YXIgaXNCaW5hcnkgPSByZUlzQmluYXJ5LnRlc3QodmFsdWUpO1xuICByZXR1cm4gKGlzQmluYXJ5IHx8IHJlSXNPY3RhbC50ZXN0KHZhbHVlKSlcbiAgICA/IGZyZWVQYXJzZUludCh2YWx1ZS5zbGljZSgyKSwgaXNCaW5hcnkgPyAyIDogOClcbiAgICA6IChyZUlzQmFkSGV4LnRlc3QodmFsdWUpID8gTkFOIDogK3ZhbHVlKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB0aHJvdHRsZTtcbiIsInZhciBnO1xyXG5cclxuLy8gVGhpcyB3b3JrcyBpbiBub24tc3RyaWN0IG1vZGVcclxuZyA9IChmdW5jdGlvbigpIHtcclxuXHRyZXR1cm4gdGhpcztcclxufSkoKTtcclxuXHJcbnRyeSB7XHJcblx0Ly8gVGhpcyB3b3JrcyBpZiBldmFsIGlzIGFsbG93ZWQgKHNlZSBDU1ApXHJcblx0ZyA9IGcgfHwgRnVuY3Rpb24oXCJyZXR1cm4gdGhpc1wiKSgpIHx8ICgxLCBldmFsKShcInRoaXNcIik7XHJcbn0gY2F0Y2ggKGUpIHtcclxuXHQvLyBUaGlzIHdvcmtzIGlmIHRoZSB3aW5kb3cgcmVmZXJlbmNlIGlzIGF2YWlsYWJsZVxyXG5cdGlmICh0eXBlb2Ygd2luZG93ID09PSBcIm9iamVjdFwiKSBnID0gd2luZG93O1xyXG59XHJcblxyXG4vLyBnIGNhbiBzdGlsbCBiZSB1bmRlZmluZWQsIGJ1dCBub3RoaW5nIHRvIGRvIGFib3V0IGl0Li4uXHJcbi8vIFdlIHJldHVybiB1bmRlZmluZWQsIGluc3RlYWQgb2Ygbm90aGluZyBoZXJlLCBzbyBpdCdzXHJcbi8vIGVhc2llciB0byBoYW5kbGUgdGhpcyBjYXNlLiBpZighZ2xvYmFsKSB7IC4uLn1cclxuXHJcbm1vZHVsZS5leHBvcnRzID0gZztcclxuIiwiLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5pbXBvcnQgeyBnZXRFbGVtZW50c0ZvclNvdXJjZUxpbmUgfSBmcm9tICcuL3Njcm9sbC1zeW5jJztcblxuZXhwb3J0IGNsYXNzIEFjdGl2ZUxpbmVNYXJrZXIge1xuXHRwcml2YXRlIF9jdXJyZW50OiBhbnk7XG5cblx0b25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uKGxpbmU6IG51bWJlcikge1xuXHRcdGNvbnN0IHsgcHJldmlvdXMgfSA9IGdldEVsZW1lbnRzRm9yU291cmNlTGluZShsaW5lKTtcblx0XHR0aGlzLl91cGRhdGUocHJldmlvdXMgJiYgcHJldmlvdXMuZWxlbWVudCk7XG5cdH1cblxuXHRfdXBkYXRlKGJlZm9yZTogSFRNTEVsZW1lbnQgfCB1bmRlZmluZWQpIHtcblx0XHR0aGlzLl91bm1hcmtBY3RpdmVFbGVtZW50KHRoaXMuX2N1cnJlbnQpO1xuXHRcdHRoaXMuX21hcmtBY3RpdmVFbGVtZW50KGJlZm9yZSk7XG5cdFx0dGhpcy5fY3VycmVudCA9IGJlZm9yZTtcblx0fVxuXG5cdF91bm1hcmtBY3RpdmVFbGVtZW50KGVsZW1lbnQ6IEhUTUxFbGVtZW50IHwgdW5kZWZpbmVkKSB7XG5cdFx0aWYgKCFlbGVtZW50KSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGVsZW1lbnQuY2xhc3NOYW1lID0gZWxlbWVudC5jbGFzc05hbWUucmVwbGFjZSgvXFxiY29kZS1hY3RpdmUtbGluZVxcYi9nLCAnJyk7XG5cdH1cblxuXHRfbWFya0FjdGl2ZUVsZW1lbnQoZWxlbWVudDogSFRNTEVsZW1lbnQgfCB1bmRlZmluZWQpIHtcblx0XHRpZiAoIWVsZW1lbnQpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0ZWxlbWVudC5jbGFzc05hbWUgKz0gJyBjb2RlLWFjdGl2ZS1saW5lJztcblx0fVxufSIsIi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG5leHBvcnQgZnVuY3Rpb24gb25jZURvY3VtZW50TG9hZGVkKGY6ICgpID0+IHZvaWQpIHtcblx0aWYgKGRvY3VtZW50LnJlYWR5U3RhdGUgPT09ICdsb2FkaW5nJyB8fCBkb2N1bWVudC5yZWFkeVN0YXRlIGFzIHN0cmluZyA9PT0gJ3VuaW5pdGlhbGl6ZWQnKSB7XG5cdFx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignRE9NQ29udGVudExvYWRlZCcsIGYpO1xuXHR9IGVsc2Uge1xuXHRcdGYoKTtcblx0fVxufSIsIi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG5pbXBvcnQgeyBBY3RpdmVMaW5lTWFya2VyIH0gZnJvbSAnLi9hY3RpdmVMaW5lTWFya2VyJztcbmltcG9ydCB7IG9uY2VEb2N1bWVudExvYWRlZCB9IGZyb20gJy4vZXZlbnRzJztcbmltcG9ydCB7IGNyZWF0ZVBvc3RlckZvclZzQ29kZSB9IGZyb20gJy4vbWVzc2FnaW5nJztcbmltcG9ydCB7IGdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0LCBzY3JvbGxUb1JldmVhbFNvdXJjZUxpbmUsIGdldExpbmVFbGVtZW50Rm9yRnJhZ21lbnQgfSBmcm9tICcuL3Njcm9sbC1zeW5jJztcbmltcG9ydCB7IGdldFNldHRpbmdzLCBnZXREYXRhIH0gZnJvbSAnLi9zZXR0aW5ncyc7XG5pbXBvcnQgdGhyb3R0bGUgPSByZXF1aXJlKCdsb2Rhc2gudGhyb3R0bGUnKTtcblxuZGVjbGFyZSB2YXIgYWNxdWlyZVZzQ29kZUFwaTogYW55O1xuXG5sZXQgc2Nyb2xsRGlzYWJsZWQgPSB0cnVlO1xuY29uc3QgbWFya2VyID0gbmV3IEFjdGl2ZUxpbmVNYXJrZXIoKTtcbmNvbnN0IHNldHRpbmdzID0gZ2V0U2V0dGluZ3MoKTtcblxuY29uc3QgdnNjb2RlID0gYWNxdWlyZVZzQ29kZUFwaSgpO1xuXG4vLyBTZXQgVlMgQ29kZSBzdGF0ZVxubGV0IHN0YXRlID0gZ2V0RGF0YTx7IGxpbmU6IG51bWJlciwgIGZyYWdtZW50OiBzdHJpbmcgfT4oJ2RhdGEtc3RhdGUnKTtcbnZzY29kZS5zZXRTdGF0ZShzdGF0ZSk7XG5cbmNvbnN0IG1lc3NhZ2luZyA9IGNyZWF0ZVBvc3RlckZvclZzQ29kZSh2c2NvZGUpO1xuXG53aW5kb3cuY3NwQWxlcnRlci5zZXRQb3N0ZXIobWVzc2FnaW5nKTtcbndpbmRvdy5zdHlsZUxvYWRpbmdNb25pdG9yLnNldFBvc3RlcihtZXNzYWdpbmcpO1xuXG53aW5kb3cub25sb2FkID0gKCkgPT4ge1xuXHR1cGRhdGVJbWFnZVNpemVzKCk7XG59O1xuXG5vbmNlRG9jdW1lbnRMb2FkZWQoKCkgPT4ge1xuXHRpZiAoc2V0dGluZ3Muc2Nyb2xsUHJldmlld1dpdGhFZGl0b3IpIHtcblx0XHRzZXRUaW1lb3V0KCgpID0+IHtcblx0XHRcdC8vIFRyeSB0byBzY3JvbGwgdG8gZnJhZ21lbnQgaWYgYXZhaWxhYmxlXG5cdFx0XHRpZiAoc3RhdGUuZnJhZ21lbnQpIHtcblx0XHRcdFx0Y29uc3QgZWxlbWVudCA9IGdldExpbmVFbGVtZW50Rm9yRnJhZ21lbnQoc3RhdGUuZnJhZ21lbnQpO1xuXHRcdFx0XHRpZiAoZWxlbWVudCkge1xuXHRcdFx0XHRcdHNjcm9sbERpc2FibGVkID0gdHJ1ZTtcblx0XHRcdFx0XHRzY3JvbGxUb1JldmVhbFNvdXJjZUxpbmUoZWxlbWVudC5saW5lKTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y29uc3QgaW5pdGlhbExpbmUgPSArc2V0dGluZ3MubGluZTtcblx0XHRcdFx0aWYgKCFpc05hTihpbml0aWFsTGluZSkpIHtcblx0XHRcdFx0XHRzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG5cdFx0XHRcdFx0c2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGluaXRpYWxMaW5lKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0sIDApO1xuXHR9XG59KTtcblxuY29uc3Qgb25VcGRhdGVWaWV3ID0gKCgpID0+IHtcblx0Y29uc3QgZG9TY3JvbGwgPSB0aHJvdHRsZSgobGluZTogbnVtYmVyKSA9PiB7XG5cdFx0c2Nyb2xsRGlzYWJsZWQgPSB0cnVlO1xuXHRcdHNjcm9sbFRvUmV2ZWFsU291cmNlTGluZShsaW5lKTtcblx0fSwgNTApO1xuXG5cdHJldHVybiAobGluZTogbnVtYmVyLCBzZXR0aW5nczogYW55KSA9PiB7XG5cdFx0aWYgKCFpc05hTihsaW5lKSkge1xuXHRcdFx0c2V0dGluZ3MubGluZSA9IGxpbmU7XG5cdFx0XHRkb1Njcm9sbChsaW5lKTtcblx0XHR9XG5cdH07XG59KSgpO1xuXG5sZXQgdXBkYXRlSW1hZ2VTaXplcyA9IHRocm90dGxlKCgpID0+IHtcblx0Y29uc3QgaW1hZ2VJbmZvOiB7IGlkOiBzdHJpbmcsIGhlaWdodDogbnVtYmVyLCB3aWR0aDogbnVtYmVyIH1bXSA9IFtdO1xuXHRsZXQgaW1hZ2VzID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2ltZycpO1xuXHRpZiAoaW1hZ2VzKSB7XG5cdFx0bGV0IGk7XG5cdFx0Zm9yIChpID0gMDsgaSA8IGltYWdlcy5sZW5ndGg7IGkrKykge1xuXHRcdFx0Y29uc3QgaW1nID0gaW1hZ2VzW2ldO1xuXG5cdFx0XHRpZiAoaW1nLmNsYXNzTGlzdC5jb250YWlucygnbG9hZGluZycpKSB7XG5cdFx0XHRcdGltZy5jbGFzc0xpc3QucmVtb3ZlKCdsb2FkaW5nJyk7XG5cdFx0XHR9XG5cblx0XHRcdGltYWdlSW5mby5wdXNoKHtcblx0XHRcdFx0aWQ6IGltZy5pZCxcblx0XHRcdFx0aGVpZ2h0OiBpbWcuaGVpZ2h0LFxuXHRcdFx0XHR3aWR0aDogaW1nLndpZHRoXG5cdFx0XHR9KTtcblx0XHR9XG5cblx0XHRtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ2NhY2hlSW1hZ2VTaXplcycsIGltYWdlSW5mbyk7XG5cdH1cbn0sIDUwKTtcblxud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsICgpID0+IHtcblx0c2Nyb2xsRGlzYWJsZWQgPSB0cnVlO1xuXHR1cGRhdGVJbWFnZVNpemVzKCk7XG59LCB0cnVlKTtcblxud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCBldmVudCA9PiB7XG5cdGlmIChldmVudC5kYXRhLnNvdXJjZSAhPT0gc2V0dGluZ3Muc291cmNlKSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0c3dpdGNoIChldmVudC5kYXRhLnR5cGUpIHtcblx0XHRjYXNlICdvbkRpZENoYW5nZVRleHRFZGl0b3JTZWxlY3Rpb24nOlxuXHRcdFx0bWFya2VyLm9uRGlkQ2hhbmdlVGV4dEVkaXRvclNlbGVjdGlvbihldmVudC5kYXRhLmxpbmUpO1xuXHRcdFx0YnJlYWs7XG5cblx0XHRjYXNlICd1cGRhdGVWaWV3Jzpcblx0XHRcdG9uVXBkYXRlVmlldyhldmVudC5kYXRhLmxpbmUsIHNldHRpbmdzKTtcblx0XHRcdGJyZWFrO1xuXHR9XG59LCBmYWxzZSk7XG5cbmRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2RibGNsaWNrJywgZXZlbnQgPT4ge1xuXHRpZiAoIXNldHRpbmdzLmRvdWJsZUNsaWNrVG9Td2l0Y2hUb0VkaXRvcikge1xuXHRcdHJldHVybjtcblx0fVxuXG5cdC8vIElnbm9yZSBjbGlja3Mgb24gbGlua3Ncblx0Zm9yIChsZXQgbm9kZSA9IGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudDsgbm9kZTsgbm9kZSA9IG5vZGUucGFyZW50Tm9kZSBhcyBIVE1MRWxlbWVudCkge1xuXHRcdGlmIChub2RlLnRhZ05hbWUgPT09ICdBJykge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0fVxuXG5cdGNvbnN0IG9mZnNldCA9IGV2ZW50LnBhZ2VZO1xuXHRjb25zdCBsaW5lID0gZ2V0RWRpdG9yTGluZU51bWJlckZvclBhZ2VPZmZzZXQob2Zmc2V0KTtcblx0aWYgKHR5cGVvZiBsaW5lID09PSAnbnVtYmVyJyAmJiAhaXNOYU4obGluZSkpIHtcblx0XHRtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ2RpZENsaWNrJywgeyBsaW5lOiBNYXRoLmZsb29yKGxpbmUpIH0pO1xuXHR9XG59KTtcblxuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBldmVudCA9PiB7XG5cdGlmICghZXZlbnQpIHtcblx0XHRyZXR1cm47XG5cdH1cblxuXHRsZXQgbm9kZTogYW55ID0gZXZlbnQudGFyZ2V0O1xuXHR3aGlsZSAobm9kZSkge1xuXHRcdGlmIChub2RlLnRhZ05hbWUgJiYgbm9kZS50YWdOYW1lID09PSAnQScgJiYgbm9kZS5ocmVmKSB7XG5cdFx0XHRpZiAobm9kZS5nZXRBdHRyaWJ1dGUoJ2hyZWYnKS5zdGFydHNXaXRoKCcjJykpIHtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0XHRpZiAobm9kZS5ocmVmLnN0YXJ0c1dpdGgoJ2ZpbGU6Ly8nKSB8fCBub2RlLmhyZWYuc3RhcnRzV2l0aCgndnNjb2RlLXJlc291cmNlOicpIHx8IG5vZGUuaHJlZi5zdGFydHNXaXRoKHNldHRpbmdzLndlYnZpZXdSZXNvdXJjZVJvb3QpKSB7XG5cdFx0XHRcdGNvbnN0IFtwYXRoLCBmcmFnbWVudF0gPSBub2RlLmhyZWYucmVwbGFjZSgvXihmaWxlOlxcL1xcL3x2c2NvZGUtcmVzb3VyY2U6KS9pLCAnJykucmVwbGFjZShuZXcgUmVnRXhwKGBeJHtlc2NhcGVSZWdFeHAoc2V0dGluZ3Mud2Vidmlld1Jlc291cmNlUm9vdCl9YCkpLnNwbGl0KCcjJyk7XG5cdFx0XHRcdG1lc3NhZ2luZy5wb3N0TWVzc2FnZSgnY2xpY2tMaW5rJywgeyBwYXRoLCBmcmFnbWVudCB9KTtcblx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0ZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdFx0YnJlYWs7XG5cdFx0fVxuXHRcdG5vZGUgPSBub2RlLnBhcmVudE5vZGU7XG5cdH1cbn0sIHRydWUpO1xuXG5pZiAoc2V0dGluZ3Muc2Nyb2xsRWRpdG9yV2l0aFByZXZpZXcpIHtcblx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIHRocm90dGxlKCgpID0+IHtcblx0XHRpZiAoc2Nyb2xsRGlzYWJsZWQpIHtcblx0XHRcdHNjcm9sbERpc2FibGVkID0gZmFsc2U7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGNvbnN0IGxpbmUgPSBnZXRFZGl0b3JMaW5lTnVtYmVyRm9yUGFnZU9mZnNldCh3aW5kb3cuc2Nyb2xsWSk7XG5cdFx0XHRpZiAodHlwZW9mIGxpbmUgPT09ICdudW1iZXInICYmICFpc05hTihsaW5lKSkge1xuXHRcdFx0XHRtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ3JldmVhbExpbmUnLCB7IGxpbmUgfSk7XG5cdFx0XHRcdHN0YXRlLmxpbmUgPSBsaW5lO1xuXHRcdFx0XHR2c2NvZGUuc2V0U3RhdGUoc3RhdGUpO1xuXHRcdFx0fVxuXHRcdH1cblx0fSwgNTApKTtcbn1cblxuZnVuY3Rpb24gZXNjYXBlUmVnRXhwKHRleHQ6IHN0cmluZykge1xuXHRyZXR1cm4gdGV4dC5yZXBsYWNlKC9bLVtcXF17fSgpKis/LixcXFxcXiR8I1xcc10vZywgJ1xcXFwkJicpO1xufVxuIiwiLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbmltcG9ydCB7IGdldFNldHRpbmdzIH0gZnJvbSAnLi9zZXR0aW5ncyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWVzc2FnZVBvc3RlciB7XG5cdC8qKlxuXHQgKiBQb3N0IGEgbWVzc2FnZSB0byB0aGUgbWFya2Rvd24gZXh0ZW5zaW9uXG5cdCAqL1xuXHRwb3N0TWVzc2FnZSh0eXBlOiBzdHJpbmcsIGJvZHk6IG9iamVjdCk6IHZvaWQ7XG59XG5cbmV4cG9ydCBjb25zdCBjcmVhdGVQb3N0ZXJGb3JWc0NvZGUgPSAodnNjb2RlOiBhbnkpID0+IHtcblx0cmV0dXJuIG5ldyBjbGFzcyBpbXBsZW1lbnRzIE1lc3NhZ2VQb3N0ZXIge1xuXHRcdHBvc3RNZXNzYWdlKHR5cGU6IHN0cmluZywgYm9keTogb2JqZWN0KTogdm9pZCB7XG5cdFx0XHR2c2NvZGUucG9zdE1lc3NhZ2Uoe1xuXHRcdFx0XHR0eXBlLFxuXHRcdFx0XHRzb3VyY2U6IGdldFNldHRpbmdzKCkuc291cmNlLFxuXHRcdFx0XHRib2R5XG5cdFx0XHR9KTtcblx0XHR9XG5cdH07XG59O1xuXG4iLCIvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuaW1wb3J0IHsgZ2V0U2V0dGluZ3MgfSBmcm9tICcuL3NldHRpbmdzJztcblxuXG5mdW5jdGlvbiBjbGFtcChtaW46IG51bWJlciwgbWF4OiBudW1iZXIsIHZhbHVlOiBudW1iZXIpIHtcblx0cmV0dXJuIE1hdGgubWluKG1heCwgTWF0aC5tYXgobWluLCB2YWx1ZSkpO1xufVxuXG5mdW5jdGlvbiBjbGFtcExpbmUobGluZTogbnVtYmVyKSB7XG5cdHJldHVybiBjbGFtcCgwLCBnZXRTZXR0aW5ncygpLmxpbmVDb3VudCAtIDEsIGxpbmUpO1xufVxuXG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29kZUxpbmVFbGVtZW50IHtcblx0ZWxlbWVudDogSFRNTEVsZW1lbnQ7XG5cdGxpbmU6IG51bWJlcjtcbn1cblxuY29uc3QgZ2V0Q29kZUxpbmVFbGVtZW50cyA9ICgoKSA9PiB7XG5cdGxldCBlbGVtZW50czogQ29kZUxpbmVFbGVtZW50W107XG5cdHJldHVybiAoKSA9PiB7XG5cdFx0aWYgKCFlbGVtZW50cykge1xuXHRcdFx0ZWxlbWVudHMgPSBbeyBlbGVtZW50OiBkb2N1bWVudC5ib2R5LCBsaW5lOiAwIH1dO1xuXHRcdFx0Zm9yIChjb25zdCBlbGVtZW50IG9mIGRvY3VtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUoJ2NvZGUtbGluZScpKSB7XG5cdFx0XHRcdGNvbnN0IGxpbmUgPSArZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtbGluZScpITtcblx0XHRcdFx0aWYgKCFpc05hTihsaW5lKSkge1xuXHRcdFx0XHRcdGVsZW1lbnRzLnB1c2goeyBlbGVtZW50OiBlbGVtZW50IGFzIEhUTUxFbGVtZW50LCBsaW5lIH0pO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiBlbGVtZW50cztcblx0fTtcbn0pKCk7XG5cbi8qKlxuICogRmluZCB0aGUgaHRtbCBlbGVtZW50cyB0aGF0IG1hcCB0byBhIHNwZWNpZmljIHRhcmdldCBsaW5lIGluIHRoZSBlZGl0b3IuXG4gKlxuICogSWYgYW4gZXhhY3QgbWF0Y2gsIHJldHVybnMgYSBzaW5nbGUgZWxlbWVudC4gSWYgdGhlIGxpbmUgaXMgYmV0d2VlbiBlbGVtZW50cyxcbiAqIHJldHVybnMgdGhlIGVsZW1lbnQgcHJpb3IgdG8gYW5kIHRoZSBlbGVtZW50IGFmdGVyIHRoZSBnaXZlbiBsaW5lLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0RWxlbWVudHNGb3JTb3VyY2VMaW5lKHRhcmdldExpbmU6IG51bWJlcik6IHsgcHJldmlvdXM6IENvZGVMaW5lRWxlbWVudDsgbmV4dD86IENvZGVMaW5lRWxlbWVudDsgfSB7XG5cdGNvbnN0IGxpbmVOdW1iZXIgPSBNYXRoLmZsb29yKHRhcmdldExpbmUpO1xuXHRjb25zdCBsaW5lcyA9IGdldENvZGVMaW5lRWxlbWVudHMoKTtcblx0bGV0IHByZXZpb3VzID0gbGluZXNbMF0gfHwgbnVsbDtcblx0Zm9yIChjb25zdCBlbnRyeSBvZiBsaW5lcykge1xuXHRcdGlmIChlbnRyeS5saW5lID09PSBsaW5lTnVtYmVyKSB7XG5cdFx0XHRyZXR1cm4geyBwcmV2aW91czogZW50cnksIG5leHQ6IHVuZGVmaW5lZCB9O1xuXHRcdH0gZWxzZSBpZiAoZW50cnkubGluZSA+IGxpbmVOdW1iZXIpIHtcblx0XHRcdHJldHVybiB7IHByZXZpb3VzLCBuZXh0OiBlbnRyeSB9O1xuXHRcdH1cblx0XHRwcmV2aW91cyA9IGVudHJ5O1xuXHR9XG5cdHJldHVybiB7IHByZXZpb3VzIH07XG59XG5cbi8qKlxuICogRmluZCB0aGUgaHRtbCBlbGVtZW50cyB0aGF0IGFyZSBhdCBhIHNwZWNpZmljIHBpeGVsIG9mZnNldCBvbiB0aGUgcGFnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExpbmVFbGVtZW50c0F0UGFnZU9mZnNldChvZmZzZXQ6IG51bWJlcik6IHsgcHJldmlvdXM6IENvZGVMaW5lRWxlbWVudDsgbmV4dD86IENvZGVMaW5lRWxlbWVudDsgfSB7XG5cdGNvbnN0IGxpbmVzID0gZ2V0Q29kZUxpbmVFbGVtZW50cygpO1xuXHRjb25zdCBwb3NpdGlvbiA9IG9mZnNldCAtIHdpbmRvdy5zY3JvbGxZO1xuXHRsZXQgbG8gPSAtMTtcblx0bGV0IGhpID0gbGluZXMubGVuZ3RoIC0gMTtcblx0d2hpbGUgKGxvICsgMSA8IGhpKSB7XG5cdFx0Y29uc3QgbWlkID0gTWF0aC5mbG9vcigobG8gKyBoaSkgLyAyKTtcblx0XHRjb25zdCBib3VuZHMgPSBsaW5lc1ttaWRdLmVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cdFx0aWYgKGJvdW5kcy50b3AgKyBib3VuZHMuaGVpZ2h0ID49IHBvc2l0aW9uKSB7XG5cdFx0XHRoaSA9IG1pZDtcblx0XHR9XG5cdFx0ZWxzZSB7XG5cdFx0XHRsbyA9IG1pZDtcblx0XHR9XG5cdH1cblx0Y29uc3QgaGlFbGVtZW50ID0gbGluZXNbaGldO1xuXHRjb25zdCBoaUJvdW5kcyA9IGhpRWxlbWVudC5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXHRpZiAoaGkgPj0gMSAmJiBoaUJvdW5kcy50b3AgPiBwb3NpdGlvbikge1xuXHRcdGNvbnN0IGxvRWxlbWVudCA9IGxpbmVzW2xvXTtcblx0XHRyZXR1cm4geyBwcmV2aW91czogbG9FbGVtZW50LCBuZXh0OiBoaUVsZW1lbnQgfTtcblx0fVxuXHRyZXR1cm4geyBwcmV2aW91czogaGlFbGVtZW50IH07XG59XG5cbi8qKlxuICogQXR0ZW1wdCB0byByZXZlYWwgdGhlIGVsZW1lbnQgZm9yIGEgc291cmNlIGxpbmUgaW4gdGhlIGVkaXRvci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNjcm9sbFRvUmV2ZWFsU291cmNlTGluZShsaW5lOiBudW1iZXIpIHtcblx0aWYgKCFnZXRTZXR0aW5ncygpLnNjcm9sbFByZXZpZXdXaXRoRWRpdG9yKSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0aWYgKGxpbmUgPD0gMCkge1xuXHRcdHdpbmRvdy5zY3JvbGwod2luZG93LnNjcm9sbFgsIDApO1xuXHRcdHJldHVybjtcblx0fVxuXG5cdGNvbnN0IHsgcHJldmlvdXMsIG5leHQgfSA9IGdldEVsZW1lbnRzRm9yU291cmNlTGluZShsaW5lKTtcblx0aWYgKCFwcmV2aW91cykge1xuXHRcdHJldHVybjtcblx0fVxuXHRsZXQgc2Nyb2xsVG8gPSAwO1xuXHRjb25zdCByZWN0ID0gcHJldmlvdXMuZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcblx0Y29uc3QgcHJldmlvdXNUb3AgPSByZWN0LnRvcDtcblx0aWYgKG5leHQgJiYgbmV4dC5saW5lICE9PSBwcmV2aW91cy5saW5lKSB7XG5cdFx0Ly8gQmV0d2VlbiB0d28gZWxlbWVudHMuIEdvIHRvIHBlcmNlbnRhZ2Ugb2Zmc2V0IGJldHdlZW4gdGhlbS5cblx0XHRjb25zdCBiZXR3ZWVuUHJvZ3Jlc3MgPSAobGluZSAtIHByZXZpb3VzLmxpbmUpIC8gKG5leHQubGluZSAtIHByZXZpb3VzLmxpbmUpO1xuXHRcdGNvbnN0IGVsZW1lbnRPZmZzZXQgPSBuZXh0LmVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkudG9wIC0gcHJldmlvdXNUb3A7XG5cdFx0c2Nyb2xsVG8gPSBwcmV2aW91c1RvcCArIGJldHdlZW5Qcm9ncmVzcyAqIGVsZW1lbnRPZmZzZXQ7XG5cdH0gZWxzZSB7XG5cdFx0Y29uc3QgcHJvZ3Jlc3NJbkVsZW1lbnQgPSBsaW5lIC0gTWF0aC5mbG9vcihsaW5lKTtcblx0XHRzY3JvbGxUbyA9IHByZXZpb3VzVG9wICsgKHJlY3QuaGVpZ2h0ICogcHJvZ3Jlc3NJbkVsZW1lbnQpO1xuXHR9XG5cdHdpbmRvdy5zY3JvbGwod2luZG93LnNjcm9sbFgsIE1hdGgubWF4KDEsIHdpbmRvdy5zY3JvbGxZICsgc2Nyb2xsVG8pKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0KG9mZnNldDogbnVtYmVyKSB7XG5cdGNvbnN0IHsgcHJldmlvdXMsIG5leHQgfSA9IGdldExpbmVFbGVtZW50c0F0UGFnZU9mZnNldChvZmZzZXQpO1xuXHRpZiAocHJldmlvdXMpIHtcblx0XHRjb25zdCBwcmV2aW91c0JvdW5kcyA9IHByZXZpb3VzLmVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cdFx0Y29uc3Qgb2Zmc2V0RnJvbVByZXZpb3VzID0gKG9mZnNldCAtIHdpbmRvdy5zY3JvbGxZIC0gcHJldmlvdXNCb3VuZHMudG9wKTtcblx0XHRpZiAobmV4dCkge1xuXHRcdFx0Y29uc3QgcHJvZ3Jlc3NCZXR3ZWVuRWxlbWVudHMgPSBvZmZzZXRGcm9tUHJldmlvdXMgLyAobmV4dC5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCAtIHByZXZpb3VzQm91bmRzLnRvcCk7XG5cdFx0XHRjb25zdCBsaW5lID0gcHJldmlvdXMubGluZSArIHByb2dyZXNzQmV0d2VlbkVsZW1lbnRzICogKG5leHQubGluZSAtIHByZXZpb3VzLmxpbmUpO1xuXHRcdFx0cmV0dXJuIGNsYW1wTGluZShsaW5lKTtcblx0XHR9XG5cdFx0ZWxzZSB7XG5cdFx0XHRjb25zdCBwcm9ncmVzc1dpdGhpbkVsZW1lbnQgPSBvZmZzZXRGcm9tUHJldmlvdXMgLyAocHJldmlvdXNCb3VuZHMuaGVpZ2h0KTtcblx0XHRcdGNvbnN0IGxpbmUgPSBwcmV2aW91cy5saW5lICsgcHJvZ3Jlc3NXaXRoaW5FbGVtZW50O1xuXHRcdFx0cmV0dXJuIGNsYW1wTGluZShsaW5lKTtcblx0XHR9XG5cdH1cblx0cmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogVHJ5IHRvIGZpbmQgdGhlIGh0bWwgZWxlbWVudCBieSB1c2luZyBhIGZyYWdtZW50IGlkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRMaW5lRWxlbWVudEZvckZyYWdtZW50KGZyYWdtZW50OiBzdHJpbmcpOiBDb2RlTGluZUVsZW1lbnQgfCB1bmRlZmluZWQge1xuXHRyZXR1cm4gZ2V0Q29kZUxpbmVFbGVtZW50cygpLmZpbmQoKGVsZW1lbnQpID0+IHtcblx0XHRyZXR1cm4gZWxlbWVudC5lbGVtZW50LmlkID09PSBmcmFnbWVudDtcblx0fSk7XG59XG4iLCIvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuZXhwb3J0IGludGVyZmFjZSBQcmV2aWV3U2V0dGluZ3Mge1xuXHRyZWFkb25seSBzb3VyY2U6IHN0cmluZztcblx0cmVhZG9ubHkgbGluZTogbnVtYmVyO1xuXHRyZWFkb25seSBsaW5lQ291bnQ6IG51bWJlcjtcblx0cmVhZG9ubHkgc2Nyb2xsUHJldmlld1dpdGhFZGl0b3I/OiBib29sZWFuO1xuXHRyZWFkb25seSBzY3JvbGxFZGl0b3JXaXRoUHJldmlldzogYm9vbGVhbjtcblx0cmVhZG9ubHkgZGlzYWJsZVNlY3VyaXR5V2FybmluZ3M6IGJvb2xlYW47XG5cdHJlYWRvbmx5IGRvdWJsZUNsaWNrVG9Td2l0Y2hUb0VkaXRvcjogYm9vbGVhbjtcblx0cmVhZG9ubHkgd2Vidmlld1Jlc291cmNlUm9vdDogc3RyaW5nO1xufVxuXG5sZXQgY2FjaGVkU2V0dGluZ3M6IFByZXZpZXdTZXR0aW5ncyB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcblxuZXhwb3J0IGZ1bmN0aW9uIGdldERhdGE8VCA9IHt9PihrZXk6IHN0cmluZyk6IFQge1xuXHRjb25zdCBlbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3ZzY29kZS1tYXJrZG93bi1wcmV2aWV3LWRhdGEnKTtcblx0aWYgKGVsZW1lbnQpIHtcblx0XHRjb25zdCBkYXRhID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoa2V5KTtcblx0XHRpZiAoZGF0YSkge1xuXHRcdFx0cmV0dXJuIEpTT04ucGFyc2UoZGF0YSk7XG5cdFx0fVxuXHR9XG5cblx0dGhyb3cgbmV3IEVycm9yKGBDb3VsZCBub3QgbG9hZCBkYXRhIGZvciAke2tleX1gKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFNldHRpbmdzKCk6IFByZXZpZXdTZXR0aW5ncyB7XG5cdGlmIChjYWNoZWRTZXR0aW5ncykge1xuXHRcdHJldHVybiBjYWNoZWRTZXR0aW5ncztcblx0fVxuXG5cdGNhY2hlZFNldHRpbmdzID0gZ2V0RGF0YSgnZGF0YS1zZXR0aW5ncycpO1xuXHRpZiAoY2FjaGVkU2V0dGluZ3MpIHtcblx0XHRyZXR1cm4gY2FjaGVkU2V0dGluZ3M7XG5cdH1cblxuXHR0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCBsb2FkIHNldHRpbmdzJyk7XG59XG4iXSwic291cmNlUm9vdCI6IiJ9 \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2xvZGFzaC50aHJvdHRsZS9pbmRleC5qcyIsIndlYnBhY2s6Ly8vKHdlYnBhY2spL2J1aWxkaW4vZ2xvYmFsLmpzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2FjdGl2ZUxpbmVNYXJrZXIudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvZXZlbnRzLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2luZGV4LnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL21lc3NhZ2luZy50cyIsIndlYnBhY2s6Ly8vLi9wcmV2aWV3LXNyYy9zY3JvbGwtc3luYy50cyIsIndlYnBhY2s6Ly8vLi9wcmV2aWV3LXNyYy9zZXR0aW5ncy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQSx5REFBaUQsY0FBYztBQUMvRDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBMkIsMEJBQTBCLEVBQUU7QUFDdkQseUNBQWlDLGVBQWU7QUFDaEQ7QUFDQTtBQUNBOztBQUVBO0FBQ0EsOERBQXNELCtEQUErRDs7QUFFckg7QUFDQTs7O0FBR0E7QUFDQTs7Ozs7Ozs7Ozs7O0FDbkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFNBQVM7QUFDcEIsV0FBVyxPQUFPO0FBQ2xCLFdBQVcsT0FBTyxZQUFZO0FBQzlCLFdBQVcsUUFBUTtBQUNuQjtBQUNBLFdBQVcsT0FBTztBQUNsQjtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLDhDQUE4QyxrQkFBa0I7QUFDaEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFNBQVM7QUFDcEIsV0FBVyxPQUFPO0FBQ2xCLFdBQVcsT0FBTyxZQUFZO0FBQzlCLFdBQVcsUUFBUTtBQUNuQjtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtREFBbUQsb0JBQW9CO0FBQ3ZFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLEVBQUU7QUFDYixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsRUFBRTtBQUNiLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0Esb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLEVBQUU7QUFDYixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxFQUFFO0FBQ2IsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOzs7Ozs7Ozs7Ozs7O0FDdGJBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsNENBQTRDOztBQUU1Qzs7Ozs7Ozs7Ozs7OztBQ25CQTtBQUNBLDhDQUE4QyxjQUFjO0FBQzVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZSxXQUFXO0FBQzFCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQzlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDLGNBQWM7QUFDNUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7O0FDZEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhDQUE4QyxjQUFjO0FBQzVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CLG1CQUFtQjtBQUN0QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQSxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUMsTUFBTTtBQUN2QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQyx5QkFBeUI7QUFDcEU7QUFDQSxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdIQUF3SCwyQ0FBMkM7QUFDbkssb0RBQW9ELGlCQUFpQjtBQUNyRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxREFBcUQsT0FBTztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsZ0NBQWdDO0FBQ2hDOzs7Ozs7Ozs7Ozs7O0FDckpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDLGNBQWM7QUFDNUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlCQUF5QixrQ0FBa0M7QUFDM0Q7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLHlCQUF5QjtBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQjtBQUNwQjtBQUNBO0FBQ0Esb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLGlCQUFpQjtBQUM1QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxpQkFBaUI7QUFDNUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOzs7Ozs7Ozs7Ozs7O0FDdklBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQ0FBK0MsSUFBSTtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJpbmRleC5qcyIsInNvdXJjZXNDb250ZW50IjpbIiBcdC8vIFRoZSBtb2R1bGUgY2FjaGVcbiBcdHZhciBpbnN0YWxsZWRNb2R1bGVzID0ge307XG5cbiBcdC8vIFRoZSByZXF1aXJlIGZ1bmN0aW9uXG4gXHRmdW5jdGlvbiBfX3dlYnBhY2tfcmVxdWlyZV9fKG1vZHVsZUlkKSB7XG5cbiBcdFx0Ly8gQ2hlY2sgaWYgbW9kdWxlIGlzIGluIGNhY2hlXG4gXHRcdGlmKGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdKSB7XG4gXHRcdFx0cmV0dXJuIGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdLmV4cG9ydHM7XG4gXHRcdH1cbiBcdFx0Ly8gQ3JlYXRlIGEgbmV3IG1vZHVsZSAoYW5kIHB1dCBpdCBpbnRvIHRoZSBjYWNoZSlcbiBcdFx0dmFyIG1vZHVsZSA9IGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdID0ge1xuIFx0XHRcdGk6IG1vZHVsZUlkLFxuIFx0XHRcdGw6IGZhbHNlLFxuIFx0XHRcdGV4cG9ydHM6IHt9XG4gXHRcdH07XG5cbiBcdFx0Ly8gRXhlY3V0ZSB0aGUgbW9kdWxlIGZ1bmN0aW9uXG4gXHRcdG1vZHVsZXNbbW9kdWxlSWRdLmNhbGwobW9kdWxlLmV4cG9ydHMsIG1vZHVsZSwgbW9kdWxlLmV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pO1xuXG4gXHRcdC8vIEZsYWcgdGhlIG1vZHVsZSBhcyBsb2FkZWRcbiBcdFx0bW9kdWxlLmwgPSB0cnVlO1xuXG4gXHRcdC8vIFJldHVybiB0aGUgZXhwb3J0cyBvZiB0aGUgbW9kdWxlXG4gXHRcdHJldHVybiBtb2R1bGUuZXhwb3J0cztcbiBcdH1cblxuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZXMgb2JqZWN0IChfX3dlYnBhY2tfbW9kdWxlc19fKVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5tID0gbW9kdWxlcztcblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGUgY2FjaGVcbiBcdF9fd2VicGFja19yZXF1aXJlX18uYyA9IGluc3RhbGxlZE1vZHVsZXM7XG5cbiBcdC8vIGRlZmluZSBnZXR0ZXIgZnVuY3Rpb24gZm9yIGhhcm1vbnkgZXhwb3J0c1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kID0gZnVuY3Rpb24oZXhwb3J0cywgbmFtZSwgZ2V0dGVyKSB7XG4gXHRcdGlmKCFfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZXhwb3J0cywgbmFtZSkpIHtcbiBcdFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgbmFtZSwge1xuIFx0XHRcdFx0Y29uZmlndXJhYmxlOiBmYWxzZSxcbiBcdFx0XHRcdGVudW1lcmFibGU6IHRydWUsXG4gXHRcdFx0XHRnZXQ6IGdldHRlclxuIFx0XHRcdH0pO1xuIFx0XHR9XG4gXHR9O1xuXG4gXHQvLyBkZWZpbmUgX19lc01vZHVsZSBvbiBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIgPSBmdW5jdGlvbihleHBvcnRzKSB7XG4gXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7XG4gXHR9O1xuXG4gXHQvLyBnZXREZWZhdWx0RXhwb3J0IGZ1bmN0aW9uIGZvciBjb21wYXRpYmlsaXR5IHdpdGggbm9uLWhhcm1vbnkgbW9kdWxlc1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5uID0gZnVuY3Rpb24obW9kdWxlKSB7XG4gXHRcdHZhciBnZXR0ZXIgPSBtb2R1bGUgJiYgbW9kdWxlLl9fZXNNb2R1bGUgP1xuIFx0XHRcdGZ1bmN0aW9uIGdldERlZmF1bHQoKSB7IHJldHVybiBtb2R1bGVbJ2RlZmF1bHQnXTsgfSA6XG4gXHRcdFx0ZnVuY3Rpb24gZ2V0TW9kdWxlRXhwb3J0cygpIHsgcmV0dXJuIG1vZHVsZTsgfTtcbiBcdFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgJ2EnLCBnZXR0ZXIpO1xuIFx0XHRyZXR1cm4gZ2V0dGVyO1xuIFx0fTtcblxuIFx0Ly8gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm8gPSBmdW5jdGlvbihvYmplY3QsIHByb3BlcnR5KSB7IHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCBwcm9wZXJ0eSk7IH07XG5cbiBcdC8vIF9fd2VicGFja19wdWJsaWNfcGF0aF9fXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnAgPSBcIlwiO1xuXG5cbiBcdC8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuIFx0cmV0dXJuIF9fd2VicGFja19yZXF1aXJlX18oX193ZWJwYWNrX3JlcXVpcmVfXy5zID0gXCIuL3ByZXZpZXctc3JjL2luZGV4LnRzXCIpO1xuIiwiLyoqXG4gKiBsb2Rhc2ggKEN1c3RvbSBCdWlsZCkgPGh0dHBzOi8vbG9kYXNoLmNvbS8+XG4gKiBCdWlsZDogYGxvZGFzaCBtb2R1bGFyaXplIGV4cG9ydHM9XCJucG1cIiAtbyAuL2BcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzIDxodHRwczovL2pxdWVyeS5vcmcvPlxuICogUmVsZWFzZWQgdW5kZXIgTUlUIGxpY2Vuc2UgPGh0dHBzOi8vbG9kYXNoLmNvbS9saWNlbnNlPlxuICogQmFzZWQgb24gVW5kZXJzY29yZS5qcyAxLjguMyA8aHR0cDovL3VuZGVyc2NvcmVqcy5vcmcvTElDRU5TRT5cbiAqIENvcHlyaWdodCBKZXJlbXkgQXNoa2VuYXMsIERvY3VtZW50Q2xvdWQgYW5kIEludmVzdGlnYXRpdmUgUmVwb3J0ZXJzICYgRWRpdG9yc1xuICovXG5cbi8qKiBVc2VkIGFzIHRoZSBgVHlwZUVycm9yYCBtZXNzYWdlIGZvciBcIkZ1bmN0aW9uc1wiIG1ldGhvZHMuICovXG52YXIgRlVOQ19FUlJPUl9URVhUID0gJ0V4cGVjdGVkIGEgZnVuY3Rpb24nO1xuXG4vKiogVXNlZCBhcyByZWZlcmVuY2VzIGZvciB2YXJpb3VzIGBOdW1iZXJgIGNvbnN0YW50cy4gKi9cbnZhciBOQU4gPSAwIC8gMDtcblxuLyoqIGBPYmplY3QjdG9TdHJpbmdgIHJlc3VsdCByZWZlcmVuY2VzLiAqL1xudmFyIHN5bWJvbFRhZyA9ICdbb2JqZWN0IFN5bWJvbF0nO1xuXG4vKiogVXNlZCB0byBtYXRjaCBsZWFkaW5nIGFuZCB0cmFpbGluZyB3aGl0ZXNwYWNlLiAqL1xudmFyIHJlVHJpbSA9IC9eXFxzK3xcXHMrJC9nO1xuXG4vKiogVXNlZCB0byBkZXRlY3QgYmFkIHNpZ25lZCBoZXhhZGVjaW1hbCBzdHJpbmcgdmFsdWVzLiAqL1xudmFyIHJlSXNCYWRIZXggPSAvXlstK10weFswLTlhLWZdKyQvaTtcblxuLyoqIFVzZWQgdG8gZGV0ZWN0IGJpbmFyeSBzdHJpbmcgdmFsdWVzLiAqL1xudmFyIHJlSXNCaW5hcnkgPSAvXjBiWzAxXSskL2k7XG5cbi8qKiBVc2VkIHRvIGRldGVjdCBvY3RhbCBzdHJpbmcgdmFsdWVzLiAqL1xudmFyIHJlSXNPY3RhbCA9IC9eMG9bMC03XSskL2k7XG5cbi8qKiBCdWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcyB3aXRob3V0IGEgZGVwZW5kZW5jeSBvbiBgcm9vdGAuICovXG52YXIgZnJlZVBhcnNlSW50ID0gcGFyc2VJbnQ7XG5cbi8qKiBEZXRlY3QgZnJlZSB2YXJpYWJsZSBgZ2xvYmFsYCBmcm9tIE5vZGUuanMuICovXG52YXIgZnJlZUdsb2JhbCA9IHR5cGVvZiBnbG9iYWwgPT0gJ29iamVjdCcgJiYgZ2xvYmFsICYmIGdsb2JhbC5PYmplY3QgPT09IE9iamVjdCAmJiBnbG9iYWw7XG5cbi8qKiBEZXRlY3QgZnJlZSB2YXJpYWJsZSBgc2VsZmAuICovXG52YXIgZnJlZVNlbGYgPSB0eXBlb2Ygc2VsZiA9PSAnb2JqZWN0JyAmJiBzZWxmICYmIHNlbGYuT2JqZWN0ID09PSBPYmplY3QgJiYgc2VsZjtcblxuLyoqIFVzZWQgYXMgYSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvYmplY3QuICovXG52YXIgcm9vdCA9IGZyZWVHbG9iYWwgfHwgZnJlZVNlbGYgfHwgRnVuY3Rpb24oJ3JldHVybiB0aGlzJykoKTtcblxuLyoqIFVzZWQgZm9yIGJ1aWx0LWluIG1ldGhvZCByZWZlcmVuY2VzLiAqL1xudmFyIG9iamVjdFByb3RvID0gT2JqZWN0LnByb3RvdHlwZTtcblxuLyoqXG4gKiBVc2VkIHRvIHJlc29sdmUgdGhlXG4gKiBbYHRvU3RyaW5nVGFnYF0oaHR0cDovL2VjbWEtaW50ZXJuYXRpb25hbC5vcmcvZWNtYS0yNjIvNy4wLyNzZWMtb2JqZWN0LnByb3RvdHlwZS50b3N0cmluZylcbiAqIG9mIHZhbHVlcy5cbiAqL1xudmFyIG9iamVjdFRvU3RyaW5nID0gb2JqZWN0UHJvdG8udG9TdHJpbmc7XG5cbi8qIEJ1aWx0LWluIG1ldGhvZCByZWZlcmVuY2VzIGZvciB0aG9zZSB3aXRoIHRoZSBzYW1lIG5hbWUgYXMgb3RoZXIgYGxvZGFzaGAgbWV0aG9kcy4gKi9cbnZhciBuYXRpdmVNYXggPSBNYXRoLm1heCxcbiAgICBuYXRpdmVNaW4gPSBNYXRoLm1pbjtcblxuLyoqXG4gKiBHZXRzIHRoZSB0aW1lc3RhbXAgb2YgdGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdGhhdCBoYXZlIGVsYXBzZWQgc2luY2VcbiAqIHRoZSBVbml4IGVwb2NoICgxIEphbnVhcnkgMTk3MCAwMDowMDowMCBVVEMpLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgMi40LjBcbiAqIEBjYXRlZ29yeSBEYXRlXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBSZXR1cm5zIHRoZSB0aW1lc3RhbXAuXG4gKiBAZXhhbXBsZVxuICpcbiAqIF8uZGVmZXIoZnVuY3Rpb24oc3RhbXApIHtcbiAqICAgY29uc29sZS5sb2coXy5ub3coKSAtIHN0YW1wKTtcbiAqIH0sIF8ubm93KCkpO1xuICogLy8gPT4gTG9ncyB0aGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBpdCB0b29rIGZvciB0aGUgZGVmZXJyZWQgaW52b2NhdGlvbi5cbiAqL1xudmFyIG5vdyA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gcm9vdC5EYXRlLm5vdygpO1xufTtcblxuLyoqXG4gKiBDcmVhdGVzIGEgZGVib3VuY2VkIGZ1bmN0aW9uIHRoYXQgZGVsYXlzIGludm9raW5nIGBmdW5jYCB1bnRpbCBhZnRlciBgd2FpdGBcbiAqIG1pbGxpc2Vjb25kcyBoYXZlIGVsYXBzZWQgc2luY2UgdGhlIGxhc3QgdGltZSB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uIHdhc1xuICogaW52b2tlZC4gVGhlIGRlYm91bmNlZCBmdW5jdGlvbiBjb21lcyB3aXRoIGEgYGNhbmNlbGAgbWV0aG9kIHRvIGNhbmNlbFxuICogZGVsYXllZCBgZnVuY2AgaW52b2NhdGlvbnMgYW5kIGEgYGZsdXNoYCBtZXRob2QgdG8gaW1tZWRpYXRlbHkgaW52b2tlIHRoZW0uXG4gKiBQcm92aWRlIGBvcHRpb25zYCB0byBpbmRpY2F0ZSB3aGV0aGVyIGBmdW5jYCBzaG91bGQgYmUgaW52b2tlZCBvbiB0aGVcbiAqIGxlYWRpbmcgYW5kL29yIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIGB3YWl0YCB0aW1lb3V0LiBUaGUgYGZ1bmNgIGlzIGludm9rZWRcbiAqIHdpdGggdGhlIGxhc3QgYXJndW1lbnRzIHByb3ZpZGVkIHRvIHRoZSBkZWJvdW5jZWQgZnVuY3Rpb24uIFN1YnNlcXVlbnRcbiAqIGNhbGxzIHRvIHRoZSBkZWJvdW5jZWQgZnVuY3Rpb24gcmV0dXJuIHRoZSByZXN1bHQgb2YgdGhlIGxhc3QgYGZ1bmNgXG4gKiBpbnZvY2F0aW9uLlxuICpcbiAqICoqTm90ZToqKiBJZiBgbGVhZGluZ2AgYW5kIGB0cmFpbGluZ2Agb3B0aW9ucyBhcmUgYHRydWVgLCBgZnVuY2AgaXNcbiAqIGludm9rZWQgb24gdGhlIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQgb25seSBpZiB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uXG4gKiBpcyBpbnZva2VkIG1vcmUgdGhhbiBvbmNlIGR1cmluZyB0aGUgYHdhaXRgIHRpbWVvdXQuXG4gKlxuICogSWYgYHdhaXRgIGlzIGAwYCBhbmQgYGxlYWRpbmdgIGlzIGBmYWxzZWAsIGBmdW5jYCBpbnZvY2F0aW9uIGlzIGRlZmVycmVkXG4gKiB1bnRpbCB0byB0aGUgbmV4dCB0aWNrLCBzaW1pbGFyIHRvIGBzZXRUaW1lb3V0YCB3aXRoIGEgdGltZW91dCBvZiBgMGAuXG4gKlxuICogU2VlIFtEYXZpZCBDb3JiYWNobydzIGFydGljbGVdKGh0dHBzOi8vY3NzLXRyaWNrcy5jb20vZGVib3VuY2luZy10aHJvdHRsaW5nLWV4cGxhaW5lZC1leGFtcGxlcy8pXG4gKiBmb3IgZGV0YWlscyBvdmVyIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIGBfLmRlYm91bmNlYCBhbmQgYF8udGhyb3R0bGVgLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgMC4xLjBcbiAqIEBjYXRlZ29yeSBGdW5jdGlvblxuICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBUaGUgZnVuY3Rpb24gdG8gZGVib3VuY2UuXG4gKiBAcGFyYW0ge251bWJlcn0gW3dhaXQ9MF0gVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gZGVsYXkuXG4gKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnM9e31dIFRoZSBvcHRpb25zIG9iamVjdC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMubGVhZGluZz1mYWxzZV1cbiAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSBsZWFkaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQuXG4gKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMubWF4V2FpdF1cbiAqICBUaGUgbWF4aW11bSB0aW1lIGBmdW5jYCBpcyBhbGxvd2VkIHRvIGJlIGRlbGF5ZWQgYmVmb3JlIGl0J3MgaW52b2tlZC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMudHJhaWxpbmc9dHJ1ZV1cbiAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgZGVib3VuY2VkIGZ1bmN0aW9uLlxuICogQGV4YW1wbGVcbiAqXG4gKiAvLyBBdm9pZCBjb3N0bHkgY2FsY3VsYXRpb25zIHdoaWxlIHRoZSB3aW5kb3cgc2l6ZSBpcyBpbiBmbHV4LlxuICogalF1ZXJ5KHdpbmRvdykub24oJ3Jlc2l6ZScsIF8uZGVib3VuY2UoY2FsY3VsYXRlTGF5b3V0LCAxNTApKTtcbiAqXG4gKiAvLyBJbnZva2UgYHNlbmRNYWlsYCB3aGVuIGNsaWNrZWQsIGRlYm91bmNpbmcgc3Vic2VxdWVudCBjYWxscy5cbiAqIGpRdWVyeShlbGVtZW50KS5vbignY2xpY2snLCBfLmRlYm91bmNlKHNlbmRNYWlsLCAzMDAsIHtcbiAqICAgJ2xlYWRpbmcnOiB0cnVlLFxuICogICAndHJhaWxpbmcnOiBmYWxzZVxuICogfSkpO1xuICpcbiAqIC8vIEVuc3VyZSBgYmF0Y2hMb2dgIGlzIGludm9rZWQgb25jZSBhZnRlciAxIHNlY29uZCBvZiBkZWJvdW5jZWQgY2FsbHMuXG4gKiB2YXIgZGVib3VuY2VkID0gXy5kZWJvdW5jZShiYXRjaExvZywgMjUwLCB7ICdtYXhXYWl0JzogMTAwMCB9KTtcbiAqIHZhciBzb3VyY2UgPSBuZXcgRXZlbnRTb3VyY2UoJy9zdHJlYW0nKTtcbiAqIGpRdWVyeShzb3VyY2UpLm9uKCdtZXNzYWdlJywgZGVib3VuY2VkKTtcbiAqXG4gKiAvLyBDYW5jZWwgdGhlIHRyYWlsaW5nIGRlYm91bmNlZCBpbnZvY2F0aW9uLlxuICogalF1ZXJ5KHdpbmRvdykub24oJ3BvcHN0YXRlJywgZGVib3VuY2VkLmNhbmNlbCk7XG4gKi9cbmZ1bmN0aW9uIGRlYm91bmNlKGZ1bmMsIHdhaXQsIG9wdGlvbnMpIHtcbiAgdmFyIGxhc3RBcmdzLFxuICAgICAgbGFzdFRoaXMsXG4gICAgICBtYXhXYWl0LFxuICAgICAgcmVzdWx0LFxuICAgICAgdGltZXJJZCxcbiAgICAgIGxhc3RDYWxsVGltZSxcbiAgICAgIGxhc3RJbnZva2VUaW1lID0gMCxcbiAgICAgIGxlYWRpbmcgPSBmYWxzZSxcbiAgICAgIG1heGluZyA9IGZhbHNlLFxuICAgICAgdHJhaWxpbmcgPSB0cnVlO1xuXG4gIGlmICh0eXBlb2YgZnVuYyAhPSAnZnVuY3Rpb24nKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihGVU5DX0VSUk9SX1RFWFQpO1xuICB9XG4gIHdhaXQgPSB0b051bWJlcih3YWl0KSB8fCAwO1xuICBpZiAoaXNPYmplY3Qob3B0aW9ucykpIHtcbiAgICBsZWFkaW5nID0gISFvcHRpb25zLmxlYWRpbmc7XG4gICAgbWF4aW5nID0gJ21heFdhaXQnIGluIG9wdGlvbnM7XG4gICAgbWF4V2FpdCA9IG1heGluZyA/IG5hdGl2ZU1heCh0b051bWJlcihvcHRpb25zLm1heFdhaXQpIHx8IDAsIHdhaXQpIDogbWF4V2FpdDtcbiAgICB0cmFpbGluZyA9ICd0cmFpbGluZycgaW4gb3B0aW9ucyA/ICEhb3B0aW9ucy50cmFpbGluZyA6IHRyYWlsaW5nO1xuICB9XG5cbiAgZnVuY3Rpb24gaW52b2tlRnVuYyh0aW1lKSB7XG4gICAgdmFyIGFyZ3MgPSBsYXN0QXJncyxcbiAgICAgICAgdGhpc0FyZyA9IGxhc3RUaGlzO1xuXG4gICAgbGFzdEFyZ3MgPSBsYXN0VGhpcyA9IHVuZGVmaW5lZDtcbiAgICBsYXN0SW52b2tlVGltZSA9IHRpbWU7XG4gICAgcmVzdWx0ID0gZnVuYy5hcHBseSh0aGlzQXJnLCBhcmdzKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gbGVhZGluZ0VkZ2UodGltZSkge1xuICAgIC8vIFJlc2V0IGFueSBgbWF4V2FpdGAgdGltZXIuXG4gICAgbGFzdEludm9rZVRpbWUgPSB0aW1lO1xuICAgIC8vIFN0YXJ0IHRoZSB0aW1lciBmb3IgdGhlIHRyYWlsaW5nIGVkZ2UuXG4gICAgdGltZXJJZCA9IHNldFRpbWVvdXQodGltZXJFeHBpcmVkLCB3YWl0KTtcbiAgICAvLyBJbnZva2UgdGhlIGxlYWRpbmcgZWRnZS5cbiAgICByZXR1cm4gbGVhZGluZyA/IGludm9rZUZ1bmModGltZSkgOiByZXN1bHQ7XG4gIH1cblxuICBmdW5jdGlvbiByZW1haW5pbmdXYWl0KHRpbWUpIHtcbiAgICB2YXIgdGltZVNpbmNlTGFzdENhbGwgPSB0aW1lIC0gbGFzdENhbGxUaW1lLFxuICAgICAgICB0aW1lU2luY2VMYXN0SW52b2tlID0gdGltZSAtIGxhc3RJbnZva2VUaW1lLFxuICAgICAgICByZXN1bHQgPSB3YWl0IC0gdGltZVNpbmNlTGFzdENhbGw7XG5cbiAgICByZXR1cm4gbWF4aW5nID8gbmF0aXZlTWluKHJlc3VsdCwgbWF4V2FpdCAtIHRpbWVTaW5jZUxhc3RJbnZva2UpIDogcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gc2hvdWxkSW52b2tlKHRpbWUpIHtcbiAgICB2YXIgdGltZVNpbmNlTGFzdENhbGwgPSB0aW1lIC0gbGFzdENhbGxUaW1lLFxuICAgICAgICB0aW1lU2luY2VMYXN0SW52b2tlID0gdGltZSAtIGxhc3RJbnZva2VUaW1lO1xuXG4gICAgLy8gRWl0aGVyIHRoaXMgaXMgdGhlIGZpcnN0IGNhbGwsIGFjdGl2aXR5IGhhcyBzdG9wcGVkIGFuZCB3ZSdyZSBhdCB0aGVcbiAgICAvLyB0cmFpbGluZyBlZGdlLCB0aGUgc3lzdGVtIHRpbWUgaGFzIGdvbmUgYmFja3dhcmRzIGFuZCB3ZSdyZSB0cmVhdGluZ1xuICAgIC8vIGl0IGFzIHRoZSB0cmFpbGluZyBlZGdlLCBvciB3ZSd2ZSBoaXQgdGhlIGBtYXhXYWl0YCBsaW1pdC5cbiAgICByZXR1cm4gKGxhc3RDYWxsVGltZSA9PT0gdW5kZWZpbmVkIHx8ICh0aW1lU2luY2VMYXN0Q2FsbCA+PSB3YWl0KSB8fFxuICAgICAgKHRpbWVTaW5jZUxhc3RDYWxsIDwgMCkgfHwgKG1heGluZyAmJiB0aW1lU2luY2VMYXN0SW52b2tlID49IG1heFdhaXQpKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHRpbWVyRXhwaXJlZCgpIHtcbiAgICB2YXIgdGltZSA9IG5vdygpO1xuICAgIGlmIChzaG91bGRJbnZva2UodGltZSkpIHtcbiAgICAgIHJldHVybiB0cmFpbGluZ0VkZ2UodGltZSk7XG4gICAgfVxuICAgIC8vIFJlc3RhcnQgdGhlIHRpbWVyLlxuICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgcmVtYWluaW5nV2FpdCh0aW1lKSk7XG4gIH1cblxuICBmdW5jdGlvbiB0cmFpbGluZ0VkZ2UodGltZSkge1xuICAgIHRpbWVySWQgPSB1bmRlZmluZWQ7XG5cbiAgICAvLyBPbmx5IGludm9rZSBpZiB3ZSBoYXZlIGBsYXN0QXJnc2Agd2hpY2ggbWVhbnMgYGZ1bmNgIGhhcyBiZWVuXG4gICAgLy8gZGVib3VuY2VkIGF0IGxlYXN0IG9uY2UuXG4gICAgaWYgKHRyYWlsaW5nICYmIGxhc3RBcmdzKSB7XG4gICAgICByZXR1cm4gaW52b2tlRnVuYyh0aW1lKTtcbiAgICB9XG4gICAgbGFzdEFyZ3MgPSBsYXN0VGhpcyA9IHVuZGVmaW5lZDtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gY2FuY2VsKCkge1xuICAgIGlmICh0aW1lcklkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aW1lcklkKTtcbiAgICB9XG4gICAgbGFzdEludm9rZVRpbWUgPSAwO1xuICAgIGxhc3RBcmdzID0gbGFzdENhbGxUaW1lID0gbGFzdFRoaXMgPSB0aW1lcklkID0gdW5kZWZpbmVkO1xuICB9XG5cbiAgZnVuY3Rpb24gZmx1c2goKSB7XG4gICAgcmV0dXJuIHRpbWVySWQgPT09IHVuZGVmaW5lZCA/IHJlc3VsdCA6IHRyYWlsaW5nRWRnZShub3coKSk7XG4gIH1cblxuICBmdW5jdGlvbiBkZWJvdW5jZWQoKSB7XG4gICAgdmFyIHRpbWUgPSBub3coKSxcbiAgICAgICAgaXNJbnZva2luZyA9IHNob3VsZEludm9rZSh0aW1lKTtcblxuICAgIGxhc3RBcmdzID0gYXJndW1lbnRzO1xuICAgIGxhc3RUaGlzID0gdGhpcztcbiAgICBsYXN0Q2FsbFRpbWUgPSB0aW1lO1xuXG4gICAgaWYgKGlzSW52b2tpbmcpIHtcbiAgICAgIGlmICh0aW1lcklkID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIGxlYWRpbmdFZGdlKGxhc3RDYWxsVGltZSk7XG4gICAgICB9XG4gICAgICBpZiAobWF4aW5nKSB7XG4gICAgICAgIC8vIEhhbmRsZSBpbnZvY2F0aW9ucyBpbiBhIHRpZ2h0IGxvb3AuXG4gICAgICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgd2FpdCk7XG4gICAgICAgIHJldHVybiBpbnZva2VGdW5jKGxhc3RDYWxsVGltZSk7XG4gICAgICB9XG4gICAgfVxuICAgIGlmICh0aW1lcklkID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgd2FpdCk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbiAgZGVib3VuY2VkLmNhbmNlbCA9IGNhbmNlbDtcbiAgZGVib3VuY2VkLmZsdXNoID0gZmx1c2g7XG4gIHJldHVybiBkZWJvdW5jZWQ7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIHRocm90dGxlZCBmdW5jdGlvbiB0aGF0IG9ubHkgaW52b2tlcyBgZnVuY2AgYXQgbW9zdCBvbmNlIHBlclxuICogZXZlcnkgYHdhaXRgIG1pbGxpc2Vjb25kcy4gVGhlIHRocm90dGxlZCBmdW5jdGlvbiBjb21lcyB3aXRoIGEgYGNhbmNlbGBcbiAqIG1ldGhvZCB0byBjYW5jZWwgZGVsYXllZCBgZnVuY2AgaW52b2NhdGlvbnMgYW5kIGEgYGZsdXNoYCBtZXRob2QgdG9cbiAqIGltbWVkaWF0ZWx5IGludm9rZSB0aGVtLiBQcm92aWRlIGBvcHRpb25zYCB0byBpbmRpY2F0ZSB3aGV0aGVyIGBmdW5jYFxuICogc2hvdWxkIGJlIGludm9rZWQgb24gdGhlIGxlYWRpbmcgYW5kL29yIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIGB3YWl0YFxuICogdGltZW91dC4gVGhlIGBmdW5jYCBpcyBpbnZva2VkIHdpdGggdGhlIGxhc3QgYXJndW1lbnRzIHByb3ZpZGVkIHRvIHRoZVxuICogdGhyb3R0bGVkIGZ1bmN0aW9uLiBTdWJzZXF1ZW50IGNhbGxzIHRvIHRoZSB0aHJvdHRsZWQgZnVuY3Rpb24gcmV0dXJuIHRoZVxuICogcmVzdWx0IG9mIHRoZSBsYXN0IGBmdW5jYCBpbnZvY2F0aW9uLlxuICpcbiAqICoqTm90ZToqKiBJZiBgbGVhZGluZ2AgYW5kIGB0cmFpbGluZ2Agb3B0aW9ucyBhcmUgYHRydWVgLCBgZnVuY2AgaXNcbiAqIGludm9rZWQgb24gdGhlIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQgb25seSBpZiB0aGUgdGhyb3R0bGVkIGZ1bmN0aW9uXG4gKiBpcyBpbnZva2VkIG1vcmUgdGhhbiBvbmNlIGR1cmluZyB0aGUgYHdhaXRgIHRpbWVvdXQuXG4gKlxuICogSWYgYHdhaXRgIGlzIGAwYCBhbmQgYGxlYWRpbmdgIGlzIGBmYWxzZWAsIGBmdW5jYCBpbnZvY2F0aW9uIGlzIGRlZmVycmVkXG4gKiB1bnRpbCB0byB0aGUgbmV4dCB0aWNrLCBzaW1pbGFyIHRvIGBzZXRUaW1lb3V0YCB3aXRoIGEgdGltZW91dCBvZiBgMGAuXG4gKlxuICogU2VlIFtEYXZpZCBDb3JiYWNobydzIGFydGljbGVdKGh0dHBzOi8vY3NzLXRyaWNrcy5jb20vZGVib3VuY2luZy10aHJvdHRsaW5nLWV4cGxhaW5lZC1leGFtcGxlcy8pXG4gKiBmb3IgZGV0YWlscyBvdmVyIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIGBfLnRocm90dGxlYCBhbmQgYF8uZGVib3VuY2VgLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgMC4xLjBcbiAqIEBjYXRlZ29yeSBGdW5jdGlvblxuICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBUaGUgZnVuY3Rpb24gdG8gdGhyb3R0bGUuXG4gKiBAcGFyYW0ge251bWJlcn0gW3dhaXQ9MF0gVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gdGhyb3R0bGUgaW52b2NhdGlvbnMgdG8uXG4gKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnM9e31dIFRoZSBvcHRpb25zIG9iamVjdC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMubGVhZGluZz10cnVlXVxuICogIFNwZWNpZnkgaW52b2tpbmcgb24gdGhlIGxlYWRpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMudHJhaWxpbmc9dHJ1ZV1cbiAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgdGhyb3R0bGVkIGZ1bmN0aW9uLlxuICogQGV4YW1wbGVcbiAqXG4gKiAvLyBBdm9pZCBleGNlc3NpdmVseSB1cGRhdGluZyB0aGUgcG9zaXRpb24gd2hpbGUgc2Nyb2xsaW5nLlxuICogalF1ZXJ5KHdpbmRvdykub24oJ3Njcm9sbCcsIF8udGhyb3R0bGUodXBkYXRlUG9zaXRpb24sIDEwMCkpO1xuICpcbiAqIC8vIEludm9rZSBgcmVuZXdUb2tlbmAgd2hlbiB0aGUgY2xpY2sgZXZlbnQgaXMgZmlyZWQsIGJ1dCBub3QgbW9yZSB0aGFuIG9uY2UgZXZlcnkgNSBtaW51dGVzLlxuICogdmFyIHRocm90dGxlZCA9IF8udGhyb3R0bGUocmVuZXdUb2tlbiwgMzAwMDAwLCB7ICd0cmFpbGluZyc6IGZhbHNlIH0pO1xuICogalF1ZXJ5KGVsZW1lbnQpLm9uKCdjbGljaycsIHRocm90dGxlZCk7XG4gKlxuICogLy8gQ2FuY2VsIHRoZSB0cmFpbGluZyB0aHJvdHRsZWQgaW52b2NhdGlvbi5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdwb3BzdGF0ZScsIHRocm90dGxlZC5jYW5jZWwpO1xuICovXG5mdW5jdGlvbiB0aHJvdHRsZShmdW5jLCB3YWl0LCBvcHRpb25zKSB7XG4gIHZhciBsZWFkaW5nID0gdHJ1ZSxcbiAgICAgIHRyYWlsaW5nID0gdHJ1ZTtcblxuICBpZiAodHlwZW9mIGZ1bmMgIT0gJ2Z1bmN0aW9uJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoRlVOQ19FUlJPUl9URVhUKTtcbiAgfVxuICBpZiAoaXNPYmplY3Qob3B0aW9ucykpIHtcbiAgICBsZWFkaW5nID0gJ2xlYWRpbmcnIGluIG9wdGlvbnMgPyAhIW9wdGlvbnMubGVhZGluZyA6IGxlYWRpbmc7XG4gICAgdHJhaWxpbmcgPSAndHJhaWxpbmcnIGluIG9wdGlvbnMgPyAhIW9wdGlvbnMudHJhaWxpbmcgOiB0cmFpbGluZztcbiAgfVxuICByZXR1cm4gZGVib3VuY2UoZnVuYywgd2FpdCwge1xuICAgICdsZWFkaW5nJzogbGVhZGluZyxcbiAgICAnbWF4V2FpdCc6IHdhaXQsXG4gICAgJ3RyYWlsaW5nJzogdHJhaWxpbmdcbiAgfSk7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgdGhlXG4gKiBbbGFuZ3VhZ2UgdHlwZV0oaHR0cDovL3d3dy5lY21hLWludGVybmF0aW9uYWwub3JnL2VjbWEtMjYyLzcuMC8jc2VjLWVjbWFzY3JpcHQtbGFuZ3VhZ2UtdHlwZXMpXG4gKiBvZiBgT2JqZWN0YC4gKGUuZy4gYXJyYXlzLCBmdW5jdGlvbnMsIG9iamVjdHMsIHJlZ2V4ZXMsIGBuZXcgTnVtYmVyKDApYCwgYW5kIGBuZXcgU3RyaW5nKCcnKWApXG4gKlxuICogQHN0YXRpY1xuICogQG1lbWJlck9mIF9cbiAqIEBzaW5jZSAwLjEuMFxuICogQGNhdGVnb3J5IExhbmdcbiAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGB2YWx1ZWAgaXMgYW4gb2JqZWN0LCBlbHNlIGBmYWxzZWAuXG4gKiBAZXhhbXBsZVxuICpcbiAqIF8uaXNPYmplY3Qoe30pO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNPYmplY3QoWzEsIDIsIDNdKTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0KF8ubm9vcCk7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc09iamVjdChudWxsKTtcbiAqIC8vID0+IGZhbHNlXG4gKi9cbmZ1bmN0aW9uIGlzT2JqZWN0KHZhbHVlKSB7XG4gIHZhciB0eXBlID0gdHlwZW9mIHZhbHVlO1xuICByZXR1cm4gISF2YWx1ZSAmJiAodHlwZSA9PSAnb2JqZWN0JyB8fCB0eXBlID09ICdmdW5jdGlvbicpO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIG9iamVjdC1saWtlLiBBIHZhbHVlIGlzIG9iamVjdC1saWtlIGlmIGl0J3Mgbm90IGBudWxsYFxuICogYW5kIGhhcyBhIGB0eXBlb2ZgIHJlc3VsdCBvZiBcIm9iamVjdFwiLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgNC4wLjBcbiAqIEBjYXRlZ29yeSBMYW5nXG4gKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiBgdmFsdWVgIGlzIG9iamVjdC1saWtlLCBlbHNlIGBmYWxzZWAuXG4gKiBAZXhhbXBsZVxuICpcbiAqIF8uaXNPYmplY3RMaWtlKHt9KTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZShbMSwgMiwgM10pO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNPYmplY3RMaWtlKF8ubm9vcCk7XG4gKiAvLyA9PiBmYWxzZVxuICpcbiAqIF8uaXNPYmplY3RMaWtlKG51bGwpO1xuICogLy8gPT4gZmFsc2VcbiAqL1xuZnVuY3Rpb24gaXNPYmplY3RMaWtlKHZhbHVlKSB7XG4gIHJldHVybiAhIXZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PSAnb2JqZWN0Jztcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBjbGFzc2lmaWVkIGFzIGEgYFN5bWJvbGAgcHJpbWl0aXZlIG9yIG9iamVjdC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDQuMC4wXG4gKiBAY2F0ZWdvcnkgTGFuZ1xuICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYHZhbHVlYCBpcyBhIHN5bWJvbCwgZWxzZSBgZmFsc2VgLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmlzU3ltYm9sKFN5bWJvbC5pdGVyYXRvcik7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc1N5bWJvbCgnYWJjJyk7XG4gKiAvLyA9PiBmYWxzZVxuICovXG5mdW5jdGlvbiBpc1N5bWJvbCh2YWx1ZSkge1xuICByZXR1cm4gdHlwZW9mIHZhbHVlID09ICdzeW1ib2wnIHx8XG4gICAgKGlzT2JqZWN0TGlrZSh2YWx1ZSkgJiYgb2JqZWN0VG9TdHJpbmcuY2FsbCh2YWx1ZSkgPT0gc3ltYm9sVGFnKTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBgdmFsdWVgIHRvIGEgbnVtYmVyLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgNC4wLjBcbiAqIEBjYXRlZ29yeSBMYW5nXG4gKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBwcm9jZXNzLlxuICogQHJldHVybnMge251bWJlcn0gUmV0dXJucyB0aGUgbnVtYmVyLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLnRvTnVtYmVyKDMuMik7XG4gKiAvLyA9PiAzLjJcbiAqXG4gKiBfLnRvTnVtYmVyKE51bWJlci5NSU5fVkFMVUUpO1xuICogLy8gPT4gNWUtMzI0XG4gKlxuICogXy50b051bWJlcihJbmZpbml0eSk7XG4gKiAvLyA9PiBJbmZpbml0eVxuICpcbiAqIF8udG9OdW1iZXIoJzMuMicpO1xuICogLy8gPT4gMy4yXG4gKi9cbmZ1bmN0aW9uIHRvTnVtYmVyKHZhbHVlKSB7XG4gIGlmICh0eXBlb2YgdmFsdWUgPT0gJ251bWJlcicpIHtcbiAgICByZXR1cm4gdmFsdWU7XG4gIH1cbiAgaWYgKGlzU3ltYm9sKHZhbHVlKSkge1xuICAgIHJldHVybiBOQU47XG4gIH1cbiAgaWYgKGlzT2JqZWN0KHZhbHVlKSkge1xuICAgIHZhciBvdGhlciA9IHR5cGVvZiB2YWx1ZS52YWx1ZU9mID09ICdmdW5jdGlvbicgPyB2YWx1ZS52YWx1ZU9mKCkgOiB2YWx1ZTtcbiAgICB2YWx1ZSA9IGlzT2JqZWN0KG90aGVyKSA/IChvdGhlciArICcnKSA6IG90aGVyO1xuICB9XG4gIGlmICh0eXBlb2YgdmFsdWUgIT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gdmFsdWUgPT09IDAgPyB2YWx1ZSA6ICt2YWx1ZTtcbiAgfVxuICB2YWx1ZSA9IHZhbHVlLnJlcGxhY2UocmVUcmltLCAnJyk7XG4gIHZhciBpc0JpbmFyeSA9IHJlSXNCaW5hcnkudGVzdCh2YWx1ZSk7XG4gIHJldHVybiAoaXNCaW5hcnkgfHwgcmVJc09jdGFsLnRlc3QodmFsdWUpKVxuICAgID8gZnJlZVBhcnNlSW50KHZhbHVlLnNsaWNlKDIpLCBpc0JpbmFyeSA/IDIgOiA4KVxuICAgIDogKHJlSXNCYWRIZXgudGVzdCh2YWx1ZSkgPyBOQU4gOiArdmFsdWUpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHRocm90dGxlO1xuIiwidmFyIGc7XHJcblxyXG4vLyBUaGlzIHdvcmtzIGluIG5vbi1zdHJpY3QgbW9kZVxyXG5nID0gKGZ1bmN0aW9uKCkge1xyXG5cdHJldHVybiB0aGlzO1xyXG59KSgpO1xyXG5cclxudHJ5IHtcclxuXHQvLyBUaGlzIHdvcmtzIGlmIGV2YWwgaXMgYWxsb3dlZCAoc2VlIENTUClcclxuXHRnID0gZyB8fCBGdW5jdGlvbihcInJldHVybiB0aGlzXCIpKCkgfHwgKDEsIGV2YWwpKFwidGhpc1wiKTtcclxufSBjYXRjaCAoZSkge1xyXG5cdC8vIFRoaXMgd29ya3MgaWYgdGhlIHdpbmRvdyByZWZlcmVuY2UgaXMgYXZhaWxhYmxlXHJcblx0aWYgKHR5cGVvZiB3aW5kb3cgPT09IFwib2JqZWN0XCIpIGcgPSB3aW5kb3c7XHJcbn1cclxuXHJcbi8vIGcgY2FuIHN0aWxsIGJlIHVuZGVmaW5lZCwgYnV0IG5vdGhpbmcgdG8gZG8gYWJvdXQgaXQuLi5cclxuLy8gV2UgcmV0dXJuIHVuZGVmaW5lZCwgaW5zdGVhZCBvZiBub3RoaW5nIGhlcmUsIHNvIGl0J3NcclxuLy8gZWFzaWVyIHRvIGhhbmRsZSB0aGlzIGNhc2UuIGlmKCFnbG9iYWwpIHsgLi4ufVxyXG5cclxubW9kdWxlLmV4cG9ydHMgPSBnO1xyXG4iLCJcInVzZSBzdHJpY3RcIjtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuY29uc3Qgc2Nyb2xsX3N5bmNfMSA9IHJlcXVpcmUoXCIuL3Njcm9sbC1zeW5jXCIpO1xuY2xhc3MgQWN0aXZlTGluZU1hcmtlciB7XG4gICAgb25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uKGxpbmUpIHtcbiAgICAgICAgY29uc3QgeyBwcmV2aW91cyB9ID0gc2Nyb2xsX3N5bmNfMS5nZXRFbGVtZW50c0ZvclNvdXJjZUxpbmUobGluZSk7XG4gICAgICAgIHRoaXMuX3VwZGF0ZShwcmV2aW91cyAmJiBwcmV2aW91cy5lbGVtZW50KTtcbiAgICB9XG4gICAgX3VwZGF0ZShiZWZvcmUpIHtcbiAgICAgICAgdGhpcy5fdW5tYXJrQWN0aXZlRWxlbWVudCh0aGlzLl9jdXJyZW50KTtcbiAgICAgICAgdGhpcy5fbWFya0FjdGl2ZUVsZW1lbnQoYmVmb3JlKTtcbiAgICAgICAgdGhpcy5fY3VycmVudCA9IGJlZm9yZTtcbiAgICB9XG4gICAgX3VubWFya0FjdGl2ZUVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlbGVtZW50LmNsYXNzTmFtZSA9IGVsZW1lbnQuY2xhc3NOYW1lLnJlcGxhY2UoL1xcYmNvZGUtYWN0aXZlLWxpbmVcXGIvZywgJycpO1xuICAgIH1cbiAgICBfbWFya0FjdGl2ZUVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlbGVtZW50LmNsYXNzTmFtZSArPSAnIGNvZGUtYWN0aXZlLWxpbmUnO1xuICAgIH1cbn1cbmV4cG9ydHMuQWN0aXZlTGluZU1hcmtlciA9IEFjdGl2ZUxpbmVNYXJrZXI7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZnVuY3Rpb24gb25jZURvY3VtZW50TG9hZGVkKGYpIHtcbiAgICBpZiAoZG9jdW1lbnQucmVhZHlTdGF0ZSA9PT0gJ2xvYWRpbmcnIHx8IGRvY3VtZW50LnJlYWR5U3RhdGUgPT09ICd1bmluaXRpYWxpemVkJykge1xuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgZik7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBmKCk7XG4gICAgfVxufVxuZXhwb3J0cy5vbmNlRG9jdW1lbnRMb2FkZWQgPSBvbmNlRG9jdW1lbnRMb2FkZWQ7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3QgYWN0aXZlTGluZU1hcmtlcl8xID0gcmVxdWlyZShcIi4vYWN0aXZlTGluZU1hcmtlclwiKTtcbmNvbnN0IGV2ZW50c18xID0gcmVxdWlyZShcIi4vZXZlbnRzXCIpO1xuY29uc3QgbWVzc2FnaW5nXzEgPSByZXF1aXJlKFwiLi9tZXNzYWdpbmdcIik7XG5jb25zdCBzY3JvbGxfc3luY18xID0gcmVxdWlyZShcIi4vc2Nyb2xsLXN5bmNcIik7XG5jb25zdCBzZXR0aW5nc18xID0gcmVxdWlyZShcIi4vc2V0dGluZ3NcIik7XG5jb25zdCB0aHJvdHRsZSA9IHJlcXVpcmUoXCJsb2Rhc2gudGhyb3R0bGVcIik7XG5sZXQgc2Nyb2xsRGlzYWJsZWQgPSB0cnVlO1xuY29uc3QgbWFya2VyID0gbmV3IGFjdGl2ZUxpbmVNYXJrZXJfMS5BY3RpdmVMaW5lTWFya2VyKCk7XG5jb25zdCBzZXR0aW5ncyA9IHNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKTtcbmNvbnN0IHZzY29kZSA9IGFjcXVpcmVWc0NvZGVBcGkoKTtcbi8vIFNldCBWUyBDb2RlIHN0YXRlXG5sZXQgc3RhdGUgPSBzZXR0aW5nc18xLmdldERhdGEoJ2RhdGEtc3RhdGUnKTtcbnZzY29kZS5zZXRTdGF0ZShzdGF0ZSk7XG5jb25zdCBtZXNzYWdpbmcgPSBtZXNzYWdpbmdfMS5jcmVhdGVQb3N0ZXJGb3JWc0NvZGUodnNjb2RlKTtcbndpbmRvdy5jc3BBbGVydGVyLnNldFBvc3RlcihtZXNzYWdpbmcpO1xud2luZG93LnN0eWxlTG9hZGluZ01vbml0b3Iuc2V0UG9zdGVyKG1lc3NhZ2luZyk7XG53aW5kb3cub25sb2FkID0gKCkgPT4ge1xuICAgIHVwZGF0ZUltYWdlU2l6ZXMoKTtcbn07XG5ldmVudHNfMS5vbmNlRG9jdW1lbnRMb2FkZWQoKCkgPT4ge1xuICAgIGlmIChzZXR0aW5ncy5zY3JvbGxQcmV2aWV3V2l0aEVkaXRvcikge1xuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIC8vIFRyeSB0byBzY3JvbGwgdG8gZnJhZ21lbnQgaWYgYXZhaWxhYmxlXG4gICAgICAgICAgICBpZiAoc3RhdGUuZnJhZ21lbnQpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBlbGVtZW50ID0gc2Nyb2xsX3N5bmNfMS5nZXRMaW5lRWxlbWVudEZvckZyYWdtZW50KHN0YXRlLmZyYWdtZW50KTtcbiAgICAgICAgICAgICAgICBpZiAoZWxlbWVudCkge1xuICAgICAgICAgICAgICAgICAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHNjcm9sbF9zeW5jXzEuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGVsZW1lbnQubGluZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc3QgaW5pdGlhbExpbmUgPSArc2V0dGluZ3MubGluZTtcbiAgICAgICAgICAgICAgICBpZiAoIWlzTmFOKGluaXRpYWxMaW5lKSkge1xuICAgICAgICAgICAgICAgICAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHNjcm9sbF9zeW5jXzEuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGluaXRpYWxMaW5lKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sIDApO1xuICAgIH1cbn0pO1xuY29uc3Qgb25VcGRhdGVWaWV3ID0gKCgpID0+IHtcbiAgICBjb25zdCBkb1Njcm9sbCA9IHRocm90dGxlKChsaW5lKSA9PiB7XG4gICAgICAgIHNjcm9sbERpc2FibGVkID0gdHJ1ZTtcbiAgICAgICAgc2Nyb2xsX3N5bmNfMS5zY3JvbGxUb1JldmVhbFNvdXJjZUxpbmUobGluZSk7XG4gICAgfSwgNTApO1xuICAgIHJldHVybiAobGluZSwgc2V0dGluZ3MpID0+IHtcbiAgICAgICAgaWYgKCFpc05hTihsaW5lKSkge1xuICAgICAgICAgICAgc2V0dGluZ3MubGluZSA9IGxpbmU7XG4gICAgICAgICAgICBkb1Njcm9sbChsaW5lKTtcbiAgICAgICAgfVxuICAgIH07XG59KSgpO1xubGV0IHVwZGF0ZUltYWdlU2l6ZXMgPSB0aHJvdHRsZSgoKSA9PiB7XG4gICAgY29uc3QgaW1hZ2VJbmZvID0gW107XG4gICAgbGV0IGltYWdlcyA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdpbWcnKTtcbiAgICBpZiAoaW1hZ2VzKSB7XG4gICAgICAgIGxldCBpO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgaW1hZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBpbWcgPSBpbWFnZXNbaV07XG4gICAgICAgICAgICBpZiAoaW1nLmNsYXNzTGlzdC5jb250YWlucygnbG9hZGluZycpKSB7XG4gICAgICAgICAgICAgICAgaW1nLmNsYXNzTGlzdC5yZW1vdmUoJ2xvYWRpbmcnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGltYWdlSW5mby5wdXNoKHtcbiAgICAgICAgICAgICAgICBpZDogaW1nLmlkLFxuICAgICAgICAgICAgICAgIGhlaWdodDogaW1nLmhlaWdodCxcbiAgICAgICAgICAgICAgICB3aWR0aDogaW1nLndpZHRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ2NhY2hlSW1hZ2VTaXplcycsIGltYWdlSW5mbyk7XG4gICAgfVxufSwgNTApO1xud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsICgpID0+IHtcbiAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgdXBkYXRlSW1hZ2VTaXplcygpO1xufSwgdHJ1ZSk7XG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIGV2ZW50ID0+IHtcbiAgICBpZiAoZXZlbnQuZGF0YS5zb3VyY2UgIT09IHNldHRpbmdzLnNvdXJjZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHN3aXRjaCAoZXZlbnQuZGF0YS50eXBlKSB7XG4gICAgICAgIGNhc2UgJ29uRGlkQ2hhbmdlVGV4dEVkaXRvclNlbGVjdGlvbic6XG4gICAgICAgICAgICBtYXJrZXIub25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uKGV2ZW50LmRhdGEubGluZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAndXBkYXRlVmlldyc6XG4gICAgICAgICAgICBvblVwZGF0ZVZpZXcoZXZlbnQuZGF0YS5saW5lLCBzZXR0aW5ncyk7XG4gICAgICAgICAgICBicmVhaztcbiAgICB9XG59LCBmYWxzZSk7XG5kb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdkYmxjbGljaycsIGV2ZW50ID0+IHtcbiAgICBpZiAoIXNldHRpbmdzLmRvdWJsZUNsaWNrVG9Td2l0Y2hUb0VkaXRvcikge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIElnbm9yZSBjbGlja3Mgb24gbGlua3NcbiAgICBmb3IgKGxldCBub2RlID0gZXZlbnQudGFyZ2V0OyBub2RlOyBub2RlID0gbm9kZS5wYXJlbnROb2RlKSB7XG4gICAgICAgIGlmIChub2RlLnRhZ05hbWUgPT09ICdBJykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbnN0IG9mZnNldCA9IGV2ZW50LnBhZ2VZO1xuICAgIGNvbnN0IGxpbmUgPSBzY3JvbGxfc3luY18xLmdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0KG9mZnNldCk7XG4gICAgaWYgKHR5cGVvZiBsaW5lID09PSAnbnVtYmVyJyAmJiAhaXNOYU4obGluZSkpIHtcbiAgICAgICAgbWVzc2FnaW5nLnBvc3RNZXNzYWdlKCdkaWRDbGljaycsIHsgbGluZTogTWF0aC5mbG9vcihsaW5lKSB9KTtcbiAgICB9XG59KTtcbmRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZXZlbnQgPT4ge1xuICAgIGlmICghZXZlbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsZXQgbm9kZSA9IGV2ZW50LnRhcmdldDtcbiAgICB3aGlsZSAobm9kZSkge1xuICAgICAgICBpZiAobm9kZS50YWdOYW1lICYmIG5vZGUudGFnTmFtZSA9PT0gJ0EnICYmIG5vZGUuaHJlZikge1xuICAgICAgICAgICAgaWYgKG5vZGUuZ2V0QXR0cmlidXRlKCdocmVmJykuc3RhcnRzV2l0aCgnIycpKSB7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobm9kZS5ocmVmLnN0YXJ0c1dpdGgoJ2ZpbGU6Ly8nKSB8fCBub2RlLmhyZWYuc3RhcnRzV2l0aCgndnNjb2RlLXJlc291cmNlOicpIHx8IG5vZGUuaHJlZi5zdGFydHNXaXRoKHNldHRpbmdzLndlYnZpZXdSZXNvdXJjZVJvb3QpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgW3BhdGgsIGZyYWdtZW50XSA9IG5vZGUuaHJlZi5yZXBsYWNlKC9eKGZpbGU6XFwvXFwvfHZzY29kZS1yZXNvdXJjZTopL2ksICcnKS5yZXBsYWNlKG5ldyBSZWdFeHAoYF4ke2VzY2FwZVJlZ0V4cChzZXR0aW5ncy53ZWJ2aWV3UmVzb3VyY2VSb290KX1gKSkuc3BsaXQoJyMnKTtcbiAgICAgICAgICAgICAgICBtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ2NsaWNrTGluaycsIHsgcGF0aCwgZnJhZ21lbnQgfSk7XG4gICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIG5vZGUgPSBub2RlLnBhcmVudE5vZGU7XG4gICAgfVxufSwgdHJ1ZSk7XG5pZiAoc2V0dGluZ3Muc2Nyb2xsRWRpdG9yV2l0aFByZXZpZXcpIHtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgdGhyb3R0bGUoKCkgPT4ge1xuICAgICAgICBpZiAoc2Nyb2xsRGlzYWJsZWQpIHtcbiAgICAgICAgICAgIHNjcm9sbERpc2FibGVkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBsaW5lID0gc2Nyb2xsX3N5bmNfMS5nZXRFZGl0b3JMaW5lTnVtYmVyRm9yUGFnZU9mZnNldCh3aW5kb3cuc2Nyb2xsWSk7XG4gICAgICAgICAgICBpZiAodHlwZW9mIGxpbmUgPT09ICdudW1iZXInICYmICFpc05hTihsaW5lKSkge1xuICAgICAgICAgICAgICAgIG1lc3NhZ2luZy5wb3N0TWVzc2FnZSgncmV2ZWFsTGluZScsIHsgbGluZSB9KTtcbiAgICAgICAgICAgICAgICBzdGF0ZS5saW5lID0gbGluZTtcbiAgICAgICAgICAgICAgICB2c2NvZGUuc2V0U3RhdGUoc3RhdGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSwgNTApKTtcbn1cbmZ1bmN0aW9uIGVzY2FwZVJlZ0V4cCh0ZXh0KSB7XG4gICAgcmV0dXJuIHRleHQucmVwbGFjZSgvWy1bXFxde30oKSorPy4sXFxcXF4kfCNcXHNdL2csICdcXFxcJCYnKTtcbn1cbiIsIlwidXNlIHN0cmljdFwiO1xuLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5jb25zdCBzZXR0aW5nc18xID0gcmVxdWlyZShcIi4vc2V0dGluZ3NcIik7XG5leHBvcnRzLmNyZWF0ZVBvc3RlckZvclZzQ29kZSA9ICh2c2NvZGUpID0+IHtcbiAgICByZXR1cm4gbmV3IGNsYXNzIHtcbiAgICAgICAgcG9zdE1lc3NhZ2UodHlwZSwgYm9keSkge1xuICAgICAgICAgICAgdnNjb2RlLnBvc3RNZXNzYWdlKHtcbiAgICAgICAgICAgICAgICB0eXBlLFxuICAgICAgICAgICAgICAgIHNvdXJjZTogc2V0dGluZ3NfMS5nZXRTZXR0aW5ncygpLnNvdXJjZSxcbiAgICAgICAgICAgICAgICBib2R5XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH07XG59O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG4vKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmNvbnN0IHNldHRpbmdzXzEgPSByZXF1aXJlKFwiLi9zZXR0aW5nc1wiKTtcbmZ1bmN0aW9uIGNsYW1wKG1pbiwgbWF4LCB2YWx1ZSkge1xuICAgIHJldHVybiBNYXRoLm1pbihtYXgsIE1hdGgubWF4KG1pbiwgdmFsdWUpKTtcbn1cbmZ1bmN0aW9uIGNsYW1wTGluZShsaW5lKSB7XG4gICAgcmV0dXJuIGNsYW1wKDAsIHNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKS5saW5lQ291bnQgLSAxLCBsaW5lKTtcbn1cbmNvbnN0IGdldENvZGVMaW5lRWxlbWVudHMgPSAoKCkgPT4ge1xuICAgIGxldCBlbGVtZW50cztcbiAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICBpZiAoIWVsZW1lbnRzKSB7XG4gICAgICAgICAgICBlbGVtZW50cyA9IFt7IGVsZW1lbnQ6IGRvY3VtZW50LmJvZHksIGxpbmU6IDAgfV07XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgZG9jdW1lbnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSgnY29kZS1saW5lJykpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBsaW5lID0gK2VsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLWxpbmUnKTtcbiAgICAgICAgICAgICAgICBpZiAoIWlzTmFOKGxpbmUpKSB7XG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnRzLnB1c2goeyBlbGVtZW50OiBlbGVtZW50LCBsaW5lIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZWxlbWVudHM7XG4gICAgfTtcbn0pKCk7XG4vKipcbiAqIEZpbmQgdGhlIGh0bWwgZWxlbWVudHMgdGhhdCBtYXAgdG8gYSBzcGVjaWZpYyB0YXJnZXQgbGluZSBpbiB0aGUgZWRpdG9yLlxuICpcbiAqIElmIGFuIGV4YWN0IG1hdGNoLCByZXR1cm5zIGEgc2luZ2xlIGVsZW1lbnQuIElmIHRoZSBsaW5lIGlzIGJldHdlZW4gZWxlbWVudHMsXG4gKiByZXR1cm5zIHRoZSBlbGVtZW50IHByaW9yIHRvIGFuZCB0aGUgZWxlbWVudCBhZnRlciB0aGUgZ2l2ZW4gbGluZS5cbiAqL1xuZnVuY3Rpb24gZ2V0RWxlbWVudHNGb3JTb3VyY2VMaW5lKHRhcmdldExpbmUpIHtcbiAgICBjb25zdCBsaW5lTnVtYmVyID0gTWF0aC5mbG9vcih0YXJnZXRMaW5lKTtcbiAgICBjb25zdCBsaW5lcyA9IGdldENvZGVMaW5lRWxlbWVudHMoKTtcbiAgICBsZXQgcHJldmlvdXMgPSBsaW5lc1swXSB8fCBudWxsO1xuICAgIGZvciAoY29uc3QgZW50cnkgb2YgbGluZXMpIHtcbiAgICAgICAgaWYgKGVudHJ5LmxpbmUgPT09IGxpbmVOdW1iZXIpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHByZXZpb3VzOiBlbnRyeSwgbmV4dDogdW5kZWZpbmVkIH07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZW50cnkubGluZSA+IGxpbmVOdW1iZXIpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHByZXZpb3VzLCBuZXh0OiBlbnRyeSB9O1xuICAgICAgICB9XG4gICAgICAgIHByZXZpb3VzID0gZW50cnk7XG4gICAgfVxuICAgIHJldHVybiB7IHByZXZpb3VzIH07XG59XG5leHBvcnRzLmdldEVsZW1lbnRzRm9yU291cmNlTGluZSA9IGdldEVsZW1lbnRzRm9yU291cmNlTGluZTtcbi8qKlxuICogRmluZCB0aGUgaHRtbCBlbGVtZW50cyB0aGF0IGFyZSBhdCBhIHNwZWNpZmljIHBpeGVsIG9mZnNldCBvbiB0aGUgcGFnZS5cbiAqL1xuZnVuY3Rpb24gZ2V0TGluZUVsZW1lbnRzQXRQYWdlT2Zmc2V0KG9mZnNldCkge1xuICAgIGNvbnN0IGxpbmVzID0gZ2V0Q29kZUxpbmVFbGVtZW50cygpO1xuICAgIGNvbnN0IHBvc2l0aW9uID0gb2Zmc2V0IC0gd2luZG93LnNjcm9sbFk7XG4gICAgbGV0IGxvID0gLTE7XG4gICAgbGV0IGhpID0gbGluZXMubGVuZ3RoIC0gMTtcbiAgICB3aGlsZSAobG8gKyAxIDwgaGkpIHtcbiAgICAgICAgY29uc3QgbWlkID0gTWF0aC5mbG9vcigobG8gKyBoaSkgLyAyKTtcbiAgICAgICAgY29uc3QgYm91bmRzID0gbGluZXNbbWlkXS5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBpZiAoYm91bmRzLnRvcCArIGJvdW5kcy5oZWlnaHQgPj0gcG9zaXRpb24pIHtcbiAgICAgICAgICAgIGhpID0gbWlkO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgbG8gPSBtaWQ7XG4gICAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgaGlFbGVtZW50ID0gbGluZXNbaGldO1xuICAgIGNvbnN0IGhpQm91bmRzID0gaGlFbGVtZW50LmVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgaWYgKGhpID49IDEgJiYgaGlCb3VuZHMudG9wID4gcG9zaXRpb24pIHtcbiAgICAgICAgY29uc3QgbG9FbGVtZW50ID0gbGluZXNbbG9dO1xuICAgICAgICByZXR1cm4geyBwcmV2aW91czogbG9FbGVtZW50LCBuZXh0OiBoaUVsZW1lbnQgfTtcbiAgICB9XG4gICAgcmV0dXJuIHsgcHJldmlvdXM6IGhpRWxlbWVudCB9O1xufVxuZXhwb3J0cy5nZXRMaW5lRWxlbWVudHNBdFBhZ2VPZmZzZXQgPSBnZXRMaW5lRWxlbWVudHNBdFBhZ2VPZmZzZXQ7XG4vKipcbiAqIEF0dGVtcHQgdG8gcmV2ZWFsIHRoZSBlbGVtZW50IGZvciBhIHNvdXJjZSBsaW5lIGluIHRoZSBlZGl0b3IuXG4gKi9cbmZ1bmN0aW9uIHNjcm9sbFRvUmV2ZWFsU291cmNlTGluZShsaW5lKSB7XG4gICAgaWYgKCFzZXR0aW5nc18xLmdldFNldHRpbmdzKCkuc2Nyb2xsUHJldmlld1dpdGhFZGl0b3IpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAobGluZSA8PSAwKSB7XG4gICAgICAgIHdpbmRvdy5zY3JvbGwod2luZG93LnNjcm9sbFgsIDApO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHsgcHJldmlvdXMsIG5leHQgfSA9IGdldEVsZW1lbnRzRm9yU291cmNlTGluZShsaW5lKTtcbiAgICBpZiAoIXByZXZpb3VzKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgbGV0IHNjcm9sbFRvID0gMDtcbiAgICBjb25zdCByZWN0ID0gcHJldmlvdXMuZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICBjb25zdCBwcmV2aW91c1RvcCA9IHJlY3QudG9wO1xuICAgIGlmIChuZXh0ICYmIG5leHQubGluZSAhPT0gcHJldmlvdXMubGluZSkge1xuICAgICAgICAvLyBCZXR3ZWVuIHR3byBlbGVtZW50cy4gR28gdG8gcGVyY2VudGFnZSBvZmZzZXQgYmV0d2VlbiB0aGVtLlxuICAgICAgICBjb25zdCBiZXR3ZWVuUHJvZ3Jlc3MgPSAobGluZSAtIHByZXZpb3VzLmxpbmUpIC8gKG5leHQubGluZSAtIHByZXZpb3VzLmxpbmUpO1xuICAgICAgICBjb25zdCBlbGVtZW50T2Zmc2V0ID0gbmV4dC5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCAtIHByZXZpb3VzVG9wO1xuICAgICAgICBzY3JvbGxUbyA9IHByZXZpb3VzVG9wICsgYmV0d2VlblByb2dyZXNzICogZWxlbWVudE9mZnNldDtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGNvbnN0IHByb2dyZXNzSW5FbGVtZW50ID0gbGluZSAtIE1hdGguZmxvb3IobGluZSk7XG4gICAgICAgIHNjcm9sbFRvID0gcHJldmlvdXNUb3AgKyAocmVjdC5oZWlnaHQgKiBwcm9ncmVzc0luRWxlbWVudCk7XG4gICAgfVxuICAgIHdpbmRvdy5zY3JvbGwod2luZG93LnNjcm9sbFgsIE1hdGgubWF4KDEsIHdpbmRvdy5zY3JvbGxZICsgc2Nyb2xsVG8pKTtcbn1cbmV4cG9ydHMuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lID0gc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lO1xuZnVuY3Rpb24gZ2V0RWRpdG9yTGluZU51bWJlckZvclBhZ2VPZmZzZXQob2Zmc2V0KSB7XG4gICAgY29uc3QgeyBwcmV2aW91cywgbmV4dCB9ID0gZ2V0TGluZUVsZW1lbnRzQXRQYWdlT2Zmc2V0KG9mZnNldCk7XG4gICAgaWYgKHByZXZpb3VzKSB7XG4gICAgICAgIGNvbnN0IHByZXZpb3VzQm91bmRzID0gcHJldmlvdXMuZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgICAgY29uc3Qgb2Zmc2V0RnJvbVByZXZpb3VzID0gKG9mZnNldCAtIHdpbmRvdy5zY3JvbGxZIC0gcHJldmlvdXNCb3VuZHMudG9wKTtcbiAgICAgICAgaWYgKG5leHQpIHtcbiAgICAgICAgICAgIGNvbnN0IHByb2dyZXNzQmV0d2VlbkVsZW1lbnRzID0gb2Zmc2V0RnJvbVByZXZpb3VzIC8gKG5leHQuZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS50b3AgLSBwcmV2aW91c0JvdW5kcy50b3ApO1xuICAgICAgICAgICAgY29uc3QgbGluZSA9IHByZXZpb3VzLmxpbmUgKyBwcm9ncmVzc0JldHdlZW5FbGVtZW50cyAqIChuZXh0LmxpbmUgLSBwcmV2aW91cy5saW5lKTtcbiAgICAgICAgICAgIHJldHVybiBjbGFtcExpbmUobGluZSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBwcm9ncmVzc1dpdGhpbkVsZW1lbnQgPSBvZmZzZXRGcm9tUHJldmlvdXMgLyAocHJldmlvdXNCb3VuZHMuaGVpZ2h0KTtcbiAgICAgICAgICAgIGNvbnN0IGxpbmUgPSBwcmV2aW91cy5saW5lICsgcHJvZ3Jlc3NXaXRoaW5FbGVtZW50O1xuICAgICAgICAgICAgcmV0dXJuIGNsYW1wTGluZShsaW5lKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cbmV4cG9ydHMuZ2V0RWRpdG9yTGluZU51bWJlckZvclBhZ2VPZmZzZXQgPSBnZXRFZGl0b3JMaW5lTnVtYmVyRm9yUGFnZU9mZnNldDtcbi8qKlxuICogVHJ5IHRvIGZpbmQgdGhlIGh0bWwgZWxlbWVudCBieSB1c2luZyBhIGZyYWdtZW50IGlkXG4gKi9cbmZ1bmN0aW9uIGdldExpbmVFbGVtZW50Rm9yRnJhZ21lbnQoZnJhZ21lbnQpIHtcbiAgICByZXR1cm4gZ2V0Q29kZUxpbmVFbGVtZW50cygpLmZpbmQoKGVsZW1lbnQpID0+IHtcbiAgICAgICAgcmV0dXJuIGVsZW1lbnQuZWxlbWVudC5pZCA9PT0gZnJhZ21lbnQ7XG4gICAgfSk7XG59XG5leHBvcnRzLmdldExpbmVFbGVtZW50Rm9yRnJhZ21lbnQgPSBnZXRMaW5lRWxlbWVudEZvckZyYWdtZW50O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG4vKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmxldCBjYWNoZWRTZXR0aW5ncyA9IHVuZGVmaW5lZDtcbmZ1bmN0aW9uIGdldERhdGEoa2V5KSB7XG4gICAgY29uc3QgZWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2c2NvZGUtbWFya2Rvd24tcHJldmlldy1kYXRhJyk7XG4gICAgaWYgKGVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgZGF0YSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKGtleSk7XG4gICAgICAgIGlmIChkYXRhKSB7XG4gICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShkYXRhKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkIG5vdCBsb2FkIGRhdGEgZm9yICR7a2V5fWApO1xufVxuZXhwb3J0cy5nZXREYXRhID0gZ2V0RGF0YTtcbmZ1bmN0aW9uIGdldFNldHRpbmdzKCkge1xuICAgIGlmIChjYWNoZWRTZXR0aW5ncykge1xuICAgICAgICByZXR1cm4gY2FjaGVkU2V0dGluZ3M7XG4gICAgfVxuICAgIGNhY2hlZFNldHRpbmdzID0gZ2V0RGF0YSgnZGF0YS1zZXR0aW5ncycpO1xuICAgIGlmIChjYWNoZWRTZXR0aW5ncykge1xuICAgICAgICByZXR1cm4gY2FjaGVkU2V0dGluZ3M7XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcignQ291bGQgbm90IGxvYWQgc2V0dGluZ3MnKTtcbn1cbmV4cG9ydHMuZ2V0U2V0dGluZ3MgPSBnZXRTZXR0aW5ncztcbiJdLCJzb3VyY2VSb290IjoiIn0= \ No newline at end of file diff --git a/extensions/markdown-language-features/media/pre.js b/extensions/markdown-language-features/media/pre.js index 5ec502df26..69a8092393 100644 --- a/extensions/markdown-language-features/media/pre.js +++ b/extensions/markdown-language-features/media/pre.js @@ -277,4 +277,4 @@ exports.getStrings = getStrings; /***/ }) /******/ }); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvY3NwLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2xvYWRpbmcudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvcHJlLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL3NldHRpbmdzLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL3N0cmluZ3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0EseURBQWlELGNBQWM7QUFDL0Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsbUNBQTJCLDBCQUEwQixFQUFFO0FBQ3ZELHlDQUFpQyxlQUFlO0FBQ2hEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDhEQUFzRCwrREFBK0Q7O0FBRXJIO0FBQ0E7OztBQUdBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDbkVBOzs7Z0dBR2dHOztBQUdoRyxzRkFBeUM7QUFDekMsbUZBQXVDO0FBRXZDOztHQUVHO0FBQ0gsTUFBYSxVQUFVO0lBTXRCO1FBTFEsWUFBTyxHQUFHLEtBQUssQ0FBQztRQUNoQixzQkFBaUIsR0FBRyxLQUFLLENBQUM7UUFLakMsUUFBUSxDQUFDLGdCQUFnQixDQUFDLHlCQUF5QixFQUFFLEdBQUcsRUFBRTtZQUN6RCxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDckIsQ0FBQyxDQUFDLENBQUM7UUFFSCxNQUFNLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDNUMsSUFBSSxLQUFLLElBQUksS0FBSyxDQUFDLElBQUksSUFBSSxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksS0FBSyxzQkFBc0IsRUFBRTtnQkFDdEUsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO2FBQ3BCO1FBQ0YsQ0FBQyxDQUFDLENBQUM7SUFDSixDQUFDO0lBRU0sU0FBUyxDQUFDLE1BQXFCO1FBQ3JDLElBQUksQ0FBQyxTQUFTLEdBQUcsTUFBTSxDQUFDO1FBQ3hCLElBQUksSUFBSSxDQUFDLGlCQUFpQixFQUFFO1lBQzNCLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztTQUN0QjtJQUNGLENBQUM7SUFFTyxZQUFZO1FBQ25CLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUM7UUFDOUIsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQ3ZCLENBQUM7SUFFTyxjQUFjO1FBQ3JCLE1BQU0sT0FBTyxHQUFHLG9CQUFVLEVBQUUsQ0FBQztRQUM3QixNQUFNLFFBQVEsR0FBRyxzQkFBVyxFQUFFLENBQUM7UUFFL0IsSUFBSSxJQUFJLENBQUMsT0FBTyxJQUFJLFFBQVEsQ0FBQyx1QkFBdUIsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDeEUsT0FBTztTQUNQO1FBQ0QsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7UUFFcEIsTUFBTSxZQUFZLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNqRCxZQUFZLENBQUMsU0FBUyxHQUFHLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQztRQUNyRCxZQUFZLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO1FBQ3BELFlBQVksQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBRWpFLFlBQVksQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQzVDLFlBQVksQ0FBQyxZQUFZLENBQUMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQ3RFLFlBQVksQ0FBQyxPQUFPLEdBQUcsR0FBRyxFQUFFO1lBQzNCLElBQUksQ0FBQyxTQUFVLENBQUMsV0FBVyxDQUFDLDZCQUE2QixFQUFFLEVBQUUsTUFBTSxFQUFFLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQ3pGLENBQUMsQ0FBQztRQUNGLFFBQVEsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQ3pDLENBQUM7Q0FDRDtBQW5ERCxnQ0FtREM7Ozs7Ozs7Ozs7Ozs7OztBQ3pERCxNQUFhLG1CQUFtQjtJQU0vQjtRQUxRLG1CQUFjLEdBQWEsRUFBRSxDQUFDO1FBQzlCLG9CQUFlLEdBQVksS0FBSyxDQUFDO1FBS3hDLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxLQUFVLEVBQUUsRUFBRTtZQUN2QyxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7WUFDM0MsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDbEMsQ0FBQyxDQUFDO1FBRUYsTUFBTSxDQUFDLGdCQUFnQixDQUFDLGtCQUFrQixFQUFFLEdBQUcsRUFBRTtZQUNoRCxLQUFLLE1BQU0sSUFBSSxJQUFJLFFBQVEsQ0FBQyxzQkFBc0IsQ0FBQyxpQkFBaUIsQ0FBa0MsRUFBRTtnQkFDdkcsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRTtvQkFDeEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxnQkFBZ0IsQ0FBQztpQkFDaEM7YUFDRDtRQUNGLENBQUMsQ0FBQyxDQUFDO1FBRUgsTUFBTSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUU7WUFDcEMsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFO2dCQUNoQyxPQUFPO2FBQ1A7WUFDRCxJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQztZQUM1QixJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUU7Z0JBQ2hCLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLHVCQUF1QixFQUFFLEVBQUUsY0FBYyxFQUFFLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDO2FBQzFGO1FBQ0YsQ0FBQyxDQUFDLENBQUM7SUFDSixDQUFDO0lBRU0sU0FBUyxDQUFDLE1BQXFCO1FBQ3JDLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksSUFBSSxDQUFDLGVBQWUsRUFBRTtZQUN6QixNQUFNLENBQUMsV0FBVyxDQUFDLHVCQUF1QixFQUFFLEVBQUUsY0FBYyxFQUFFLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDO1NBQ3JGO0lBQ0YsQ0FBQztDQUNEO0FBckNELGtEQXFDQzs7Ozs7Ozs7Ozs7Ozs7QUMzQ0Q7OztnR0FHZ0c7O0FBRWhHLHVFQUFtQztBQUNuQyxtRkFBZ0Q7QUFTaEQsTUFBTSxDQUFDLFVBQVUsR0FBRyxJQUFJLGdCQUFVLEVBQUUsQ0FBQztBQUNyQyxNQUFNLENBQUMsbUJBQW1CLEdBQUcsSUFBSSw2QkFBbUIsRUFBRSxDQUFDOzs7Ozs7Ozs7Ozs7OztBQ2hCdkQ7OztnR0FHZ0c7O0FBYWhHLElBQUksY0FBYyxHQUFnQyxTQUFTLENBQUM7QUFFNUQsU0FBZ0IsT0FBTyxDQUFTLEdBQVc7SUFDMUMsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDLGNBQWMsQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO0lBQ3hFLElBQUksT0FBTyxFQUFFO1FBQ1osTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN2QyxJQUFJLElBQUksRUFBRTtZQUNULE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUN4QjtLQUNEO0lBRUQsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsR0FBRyxFQUFFLENBQUMsQ0FBQztBQUNuRCxDQUFDO0FBVkQsMEJBVUM7QUFFRCxTQUFnQixXQUFXO0lBQzFCLElBQUksY0FBYyxFQUFFO1FBQ25CLE9BQU8sY0FBYyxDQUFDO0tBQ3RCO0lBRUQsY0FBYyxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUMxQyxJQUFJLGNBQWMsRUFBRTtRQUNuQixPQUFPLGNBQWMsQ0FBQztLQUN0QjtJQUVELE1BQU0sSUFBSSxLQUFLLENBQUMseUJBQXlCLENBQUMsQ0FBQztBQUM1QyxDQUFDO0FBWEQsa0NBV0M7Ozs7Ozs7Ozs7Ozs7O0FDekNEOzs7Z0dBR2dHOztBQUVoRyxTQUFnQixVQUFVO0lBQ3pCLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxjQUFjLENBQUMsOEJBQThCLENBQUMsQ0FBQztJQUN0RSxJQUFJLEtBQUssRUFBRTtRQUNWLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxZQUFZLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDaEQsSUFBSSxJQUFJLEVBQUU7WUFDVCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDeEI7S0FDRDtJQUNELE1BQU0sSUFBSSxLQUFLLENBQUMsd0JBQXdCLENBQUMsQ0FBQztBQUMzQyxDQUFDO0FBVEQsZ0NBU0MiLCJmaWxlIjoicHJlLmpzIiwic291cmNlc0NvbnRlbnQiOlsiIFx0Ly8gVGhlIG1vZHVsZSBjYWNoZVxuIFx0dmFyIGluc3RhbGxlZE1vZHVsZXMgPSB7fTtcblxuIFx0Ly8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbiBcdGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblxuIFx0XHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcbiBcdFx0aWYoaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0pIHtcbiBcdFx0XHRyZXR1cm4gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0uZXhwb3J0cztcbiBcdFx0fVxuIFx0XHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuIFx0XHR2YXIgbW9kdWxlID0gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0gPSB7XG4gXHRcdFx0aTogbW9kdWxlSWQsXG4gXHRcdFx0bDogZmFsc2UsXG4gXHRcdFx0ZXhwb3J0czoge31cbiBcdFx0fTtcblxuIFx0XHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cbiBcdFx0bW9kdWxlc1ttb2R1bGVJZF0uY2FsbChtb2R1bGUuZXhwb3J0cywgbW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cbiBcdFx0Ly8gRmxhZyB0aGUgbW9kdWxlIGFzIGxvYWRlZFxuIFx0XHRtb2R1bGUubCA9IHRydWU7XG5cbiBcdFx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcbiBcdFx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xuIFx0fVxuXG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlcyBvYmplY3QgKF9fd2VicGFja19tb2R1bGVzX18pXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm0gPSBtb2R1bGVzO1xuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZSBjYWNoZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5jID0gaW5zdGFsbGVkTW9kdWxlcztcblxuIFx0Ly8gZGVmaW5lIGdldHRlciBmdW5jdGlvbiBmb3IgaGFybW9ueSBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQgPSBmdW5jdGlvbihleHBvcnRzLCBuYW1lLCBnZXR0ZXIpIHtcbiBcdFx0aWYoIV9fd2VicGFja19yZXF1aXJlX18ubyhleHBvcnRzLCBuYW1lKSkge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBuYW1lLCB7XG4gXHRcdFx0XHRjb25maWd1cmFibGU6IGZhbHNlLFxuIFx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcbiBcdFx0XHRcdGdldDogZ2V0dGVyXG4gXHRcdFx0fSk7XG4gXHRcdH1cbiBcdH07XG5cbiBcdC8vIGRlZmluZSBfX2VzTW9kdWxlIG9uIGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uciA9IGZ1bmN0aW9uKGV4cG9ydHMpIHtcbiBcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogdHJ1ZSB9KTtcbiBcdH07XG5cbiBcdC8vIGdldERlZmF1bHRFeHBvcnQgZnVuY3Rpb24gZm9yIGNvbXBhdGliaWxpdHkgd2l0aCBub24taGFybW9ueSBtb2R1bGVzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm4gPSBmdW5jdGlvbihtb2R1bGUpIHtcbiBcdFx0dmFyIGdldHRlciA9IG1vZHVsZSAmJiBtb2R1bGUuX19lc01vZHVsZSA/XG4gXHRcdFx0ZnVuY3Rpb24gZ2V0RGVmYXVsdCgpIHsgcmV0dXJuIG1vZHVsZVsnZGVmYXVsdCddOyB9IDpcbiBcdFx0XHRmdW5jdGlvbiBnZXRNb2R1bGVFeHBvcnRzKCkgeyByZXR1cm4gbW9kdWxlOyB9O1xuIFx0XHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQoZ2V0dGVyLCAnYScsIGdldHRlcik7XG4gXHRcdHJldHVybiBnZXR0ZXI7XG4gXHR9O1xuXG4gXHQvLyBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGxcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubyA9IGZ1bmN0aW9uKG9iamVjdCwgcHJvcGVydHkpIHsgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmplY3QsIHByb3BlcnR5KTsgfTtcblxuIFx0Ly8gX193ZWJwYWNrX3B1YmxpY19wYXRoX19cbiBcdF9fd2VicGFja19yZXF1aXJlX18ucCA9IFwiXCI7XG5cblxuIFx0Ly8gTG9hZCBlbnRyeSBtb2R1bGUgYW5kIHJldHVybiBleHBvcnRzXG4gXHRyZXR1cm4gX193ZWJwYWNrX3JlcXVpcmVfXyhfX3dlYnBhY2tfcmVxdWlyZV9fLnMgPSBcIi4vcHJldmlldy1zcmMvcHJlLnRzXCIpO1xuIiwiLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbmltcG9ydCB7IE1lc3NhZ2VQb3N0ZXIgfSBmcm9tICcuL21lc3NhZ2luZyc7XG5pbXBvcnQgeyBnZXRTZXR0aW5ncyB9IGZyb20gJy4vc2V0dGluZ3MnO1xuaW1wb3J0IHsgZ2V0U3RyaW5ncyB9IGZyb20gJy4vc3RyaW5ncyc7XG5cbi8qKlxuICogU2hvd3MgYW4gYWxlcnQgd2hlbiB0aGVyZSBpcyBhIGNvbnRlbnQgc2VjdXJpdHkgcG9saWN5IHZpb2xhdGlvbi5cbiAqL1xuZXhwb3J0IGNsYXNzIENzcEFsZXJ0ZXIge1xuXHRwcml2YXRlIGRpZFNob3cgPSBmYWxzZTtcblx0cHJpdmF0ZSBkaWRIYXZlQ3NwV2FybmluZyA9IGZhbHNlO1xuXG5cdHByaXZhdGUgbWVzc2FnaW5nPzogTWVzc2FnZVBvc3RlcjtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblx0XHRkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdzZWN1cml0eXBvbGljeXZpb2xhdGlvbicsICgpID0+IHtcblx0XHRcdHRoaXMub25Dc3BXYXJuaW5nKCk7XG5cdFx0fSk7XG5cblx0XHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIChldmVudCkgPT4ge1xuXHRcdFx0aWYgKGV2ZW50ICYmIGV2ZW50LmRhdGEgJiYgZXZlbnQuZGF0YS5uYW1lID09PSAndnNjb2RlLWRpZC1ibG9jay1zdmcnKSB7XG5cdFx0XHRcdHRoaXMub25Dc3BXYXJuaW5nKCk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cblxuXHRwdWJsaWMgc2V0UG9zdGVyKHBvc3RlcjogTWVzc2FnZVBvc3Rlcikge1xuXHRcdHRoaXMubWVzc2FnaW5nID0gcG9zdGVyO1xuXHRcdGlmICh0aGlzLmRpZEhhdmVDc3BXYXJuaW5nKSB7XG5cdFx0XHR0aGlzLnNob3dDc3BXYXJuaW5nKCk7XG5cdFx0fVxuXHR9XG5cblx0cHJpdmF0ZSBvbkNzcFdhcm5pbmcoKSB7XG5cdFx0dGhpcy5kaWRIYXZlQ3NwV2FybmluZyA9IHRydWU7XG5cdFx0dGhpcy5zaG93Q3NwV2FybmluZygpO1xuXHR9XG5cblx0cHJpdmF0ZSBzaG93Q3NwV2FybmluZygpIHtcblx0XHRjb25zdCBzdHJpbmdzID0gZ2V0U3RyaW5ncygpO1xuXHRcdGNvbnN0IHNldHRpbmdzID0gZ2V0U2V0dGluZ3MoKTtcblxuXHRcdGlmICh0aGlzLmRpZFNob3cgfHwgc2V0dGluZ3MuZGlzYWJsZVNlY3VyaXR5V2FybmluZ3MgfHwgIXRoaXMubWVzc2FnaW5nKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdHRoaXMuZGlkU2hvdyA9IHRydWU7XG5cblx0XHRjb25zdCBub3RpZmljYXRpb24gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XG5cdFx0bm90aWZpY2F0aW9uLmlubmVyVGV4dCA9IHN0cmluZ3MuY3NwQWxlcnRNZXNzYWdlVGV4dDtcblx0XHRub3RpZmljYXRpb24uc2V0QXR0cmlidXRlKCdpZCcsICdjb2RlLWNzcC13YXJuaW5nJyk7XG5cdFx0bm90aWZpY2F0aW9uLnNldEF0dHJpYnV0ZSgndGl0bGUnLCBzdHJpbmdzLmNzcEFsZXJ0TWVzc2FnZVRpdGxlKTtcblxuXHRcdG5vdGlmaWNhdGlvbi5zZXRBdHRyaWJ1dGUoJ3JvbGUnLCAnYnV0dG9uJyk7XG5cdFx0bm90aWZpY2F0aW9uLnNldEF0dHJpYnV0ZSgnYXJpYS1sYWJlbCcsIHN0cmluZ3MuY3NwQWxlcnRNZXNzYWdlTGFiZWwpO1xuXHRcdG5vdGlmaWNhdGlvbi5vbmNsaWNrID0gKCkgPT4ge1xuXHRcdFx0dGhpcy5tZXNzYWdpbmchLnBvc3RNZXNzYWdlKCdzaG93UHJldmlld1NlY3VyaXR5U2VsZWN0b3InLCB7IHNvdXJjZTogc2V0dGluZ3Muc291cmNlIH0pO1xuXHRcdH07XG5cdFx0ZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChub3RpZmljYXRpb24pO1xuXHR9XG59XG4iLCIvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbmltcG9ydCB7IE1lc3NhZ2VQb3N0ZXIgfSBmcm9tICcuL21lc3NhZ2luZyc7XG5cbmV4cG9ydCBjbGFzcyBTdHlsZUxvYWRpbmdNb25pdG9yIHtcblx0cHJpdmF0ZSB1bmxvYWRlZFN0eWxlczogc3RyaW5nW10gPSBbXTtcblx0cHJpdmF0ZSBmaW5pc2hlZExvYWRpbmc6IGJvb2xlYW4gPSBmYWxzZTtcblxuXHRwcml2YXRlIHBvc3Rlcj86IE1lc3NhZ2VQb3N0ZXI7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cdFx0Y29uc3Qgb25TdHlsZUxvYWRFcnJvciA9IChldmVudDogYW55KSA9PiB7XG5cdFx0XHRjb25zdCBzb3VyY2UgPSBldmVudC50YXJnZXQuZGF0YXNldC5zb3VyY2U7XG5cdFx0XHR0aGlzLnVubG9hZGVkU3R5bGVzLnB1c2goc291cmNlKTtcblx0XHR9O1xuXG5cdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ0RPTUNvbnRlbnRMb2FkZWQnLCAoKSA9PiB7XG5cdFx0XHRmb3IgKGNvbnN0IGxpbmsgb2YgZG9jdW1lbnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSgnY29kZS11c2VyLXN0eWxlJykgYXMgSFRNTENvbGxlY3Rpb25PZjxIVE1MRWxlbWVudD4pIHtcblx0XHRcdFx0aWYgKGxpbmsuZGF0YXNldC5zb3VyY2UpIHtcblx0XHRcdFx0XHRsaW5rLm9uZXJyb3IgPSBvblN0eWxlTG9hZEVycm9yO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSk7XG5cblx0XHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsICgpID0+IHtcblx0XHRcdGlmICghdGhpcy51bmxvYWRlZFN0eWxlcy5sZW5ndGgpIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5maW5pc2hlZExvYWRpbmcgPSB0cnVlO1xuXHRcdFx0aWYgKHRoaXMucG9zdGVyKSB7XG5cdFx0XHRcdHRoaXMucG9zdGVyLnBvc3RNZXNzYWdlKCdwcmV2aWV3U3R5bGVMb2FkRXJyb3InLCB7IHVubG9hZGVkU3R5bGVzOiB0aGlzLnVubG9hZGVkU3R5bGVzIH0pO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHR9XG5cblx0cHVibGljIHNldFBvc3Rlcihwb3N0ZXI6IE1lc3NhZ2VQb3N0ZXIpOiB2b2lkIHtcblx0XHR0aGlzLnBvc3RlciA9IHBvc3Rlcjtcblx0XHRpZiAodGhpcy5maW5pc2hlZExvYWRpbmcpIHtcblx0XHRcdHBvc3Rlci5wb3N0TWVzc2FnZSgncHJldmlld1N0eWxlTG9hZEVycm9yJywgeyB1bmxvYWRlZFN0eWxlczogdGhpcy51bmxvYWRlZFN0eWxlcyB9KTtcblx0XHR9XG5cdH1cbn0iLCIvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuaW1wb3J0IHsgQ3NwQWxlcnRlciB9IGZyb20gJy4vY3NwJztcbmltcG9ydCB7IFN0eWxlTG9hZGluZ01vbml0b3IgfSBmcm9tICcuL2xvYWRpbmcnO1xuXG5kZWNsYXJlIGdsb2JhbCB7XG5cdGludGVyZmFjZSBXaW5kb3cge1xuXHRcdGNzcEFsZXJ0ZXI6IENzcEFsZXJ0ZXI7XG5cdFx0c3R5bGVMb2FkaW5nTW9uaXRvcjogU3R5bGVMb2FkaW5nTW9uaXRvcjtcblx0fVxufVxuXG53aW5kb3cuY3NwQWxlcnRlciA9IG5ldyBDc3BBbGVydGVyKCk7XG53aW5kb3cuc3R5bGVMb2FkaW5nTW9uaXRvciA9IG5ldyBTdHlsZUxvYWRpbmdNb25pdG9yKCk7IiwiLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbmV4cG9ydCBpbnRlcmZhY2UgUHJldmlld1NldHRpbmdzIHtcblx0cmVhZG9ubHkgc291cmNlOiBzdHJpbmc7XG5cdHJlYWRvbmx5IGxpbmU6IG51bWJlcjtcblx0cmVhZG9ubHkgbGluZUNvdW50OiBudW1iZXI7XG5cdHJlYWRvbmx5IHNjcm9sbFByZXZpZXdXaXRoRWRpdG9yPzogYm9vbGVhbjtcblx0cmVhZG9ubHkgc2Nyb2xsRWRpdG9yV2l0aFByZXZpZXc6IGJvb2xlYW47XG5cdHJlYWRvbmx5IGRpc2FibGVTZWN1cml0eVdhcm5pbmdzOiBib29sZWFuO1xuXHRyZWFkb25seSBkb3VibGVDbGlja1RvU3dpdGNoVG9FZGl0b3I6IGJvb2xlYW47XG5cdHJlYWRvbmx5IHdlYnZpZXdSZXNvdXJjZVJvb3Q6IHN0cmluZztcbn1cblxubGV0IGNhY2hlZFNldHRpbmdzOiBQcmV2aWV3U2V0dGluZ3MgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXREYXRhPFQgPSB7fT4oa2V5OiBzdHJpbmcpOiBUIHtcblx0Y29uc3QgZWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2c2NvZGUtbWFya2Rvd24tcHJldmlldy1kYXRhJyk7XG5cdGlmIChlbGVtZW50KSB7XG5cdFx0Y29uc3QgZGF0YSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKGtleSk7XG5cdFx0aWYgKGRhdGEpIHtcblx0XHRcdHJldHVybiBKU09OLnBhcnNlKGRhdGEpO1xuXHRcdH1cblx0fVxuXG5cdHRocm93IG5ldyBFcnJvcihgQ291bGQgbm90IGxvYWQgZGF0YSBmb3IgJHtrZXl9YCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRTZXR0aW5ncygpOiBQcmV2aWV3U2V0dGluZ3Mge1xuXHRpZiAoY2FjaGVkU2V0dGluZ3MpIHtcblx0XHRyZXR1cm4gY2FjaGVkU2V0dGluZ3M7XG5cdH1cblxuXHRjYWNoZWRTZXR0aW5ncyA9IGdldERhdGEoJ2RhdGEtc2V0dGluZ3MnKTtcblx0aWYgKGNhY2hlZFNldHRpbmdzKSB7XG5cdFx0cmV0dXJuIGNhY2hlZFNldHRpbmdzO1xuXHR9XG5cblx0dGhyb3cgbmV3IEVycm9yKCdDb3VsZCBub3QgbG9hZCBzZXR0aW5ncycpO1xufVxuIiwiLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRTdHJpbmdzKCk6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH0ge1xuXHRjb25zdCBzdG9yZSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2c2NvZGUtbWFya2Rvd24tcHJldmlldy1kYXRhJyk7XG5cdGlmIChzdG9yZSkge1xuXHRcdGNvbnN0IGRhdGEgPSBzdG9yZS5nZXRBdHRyaWJ1dGUoJ2RhdGEtc3RyaW5ncycpO1xuXHRcdGlmIChkYXRhKSB7XG5cdFx0XHRyZXR1cm4gSlNPTi5wYXJzZShkYXRhKTtcblx0XHR9XG5cdH1cblx0dGhyb3cgbmV3IEVycm9yKCdDb3VsZCBub3QgbG9hZCBzdHJpbmdzJyk7XG59XG4iXSwic291cmNlUm9vdCI6IiJ9 +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvY3NwLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2xvYWRpbmcudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvcHJlLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL3NldHRpbmdzLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL3N0cmluZ3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0EseURBQWlELGNBQWM7QUFDL0Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsbUNBQTJCLDBCQUEwQixFQUFFO0FBQ3ZELHlDQUFpQyxlQUFlO0FBQ2hEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDhEQUFzRCwrREFBK0Q7O0FBRXJIO0FBQ0E7OztBQUdBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7QUNuRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhDQUE4QyxjQUFjO0FBQzVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1RUFBdUUsMEJBQTBCO0FBQ2pHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7QUNyREE7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtFQUFrRSxzQ0FBc0M7QUFDeEc7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5REFBeUQsc0NBQXNDO0FBQy9GO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7O0FDbENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQ0FBK0MsSUFBSTtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQzVCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDLGNBQWM7QUFDNUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJwcmUuanMiLCJzb3VyY2VzQ29udGVudCI6WyIgXHQvLyBUaGUgbW9kdWxlIGNhY2hlXG4gXHR2YXIgaW5zdGFsbGVkTW9kdWxlcyA9IHt9O1xuXG4gXHQvLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuIFx0ZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXG4gXHRcdC8vIENoZWNrIGlmIG1vZHVsZSBpcyBpbiBjYWNoZVxuIFx0XHRpZihpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSkge1xuIFx0XHRcdHJldHVybiBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXS5leHBvcnRzO1xuIFx0XHR9XG4gXHRcdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG4gXHRcdHZhciBtb2R1bGUgPSBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSA9IHtcbiBcdFx0XHRpOiBtb2R1bGVJZCxcbiBcdFx0XHRsOiBmYWxzZSxcbiBcdFx0XHRleHBvcnRzOiB7fVxuIFx0XHR9O1xuXG4gXHRcdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuIFx0XHRtb2R1bGVzW21vZHVsZUlkXS5jYWxsKG1vZHVsZS5leHBvcnRzLCBtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuIFx0XHQvLyBGbGFnIHRoZSBtb2R1bGUgYXMgbG9hZGVkXG4gXHRcdG1vZHVsZS5sID0gdHJ1ZTtcblxuIFx0XHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuIFx0XHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG4gXHR9XG5cblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGVzIG9iamVjdCAoX193ZWJwYWNrX21vZHVsZXNfXylcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubSA9IG1vZHVsZXM7XG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlIGNhY2hlXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmMgPSBpbnN0YWxsZWRNb2R1bGVzO1xuXG4gXHQvLyBkZWZpbmUgZ2V0dGVyIGZ1bmN0aW9uIGZvciBoYXJtb255IGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uZCA9IGZ1bmN0aW9uKGV4cG9ydHMsIG5hbWUsIGdldHRlcikge1xuIFx0XHRpZighX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIG5hbWUpKSB7XG4gXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIG5hbWUsIHtcbiBcdFx0XHRcdGNvbmZpZ3VyYWJsZTogZmFsc2UsXG4gXHRcdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxuIFx0XHRcdFx0Z2V0OiBnZXR0ZXJcbiBcdFx0XHR9KTtcbiBcdFx0fVxuIFx0fTtcblxuIFx0Ly8gZGVmaW5lIF9fZXNNb2R1bGUgb24gZXhwb3J0c1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5yID0gZnVuY3Rpb24oZXhwb3J0cykge1xuIFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgJ19fZXNNb2R1bGUnLCB7IHZhbHVlOiB0cnVlIH0pO1xuIFx0fTtcblxuIFx0Ly8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubiA9IGZ1bmN0aW9uKG1vZHVsZSkge1xuIFx0XHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cbiBcdFx0XHRmdW5jdGlvbiBnZXREZWZhdWx0KCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxuIFx0XHRcdGZ1bmN0aW9uIGdldE1vZHVsZUV4cG9ydHMoKSB7IHJldHVybiBtb2R1bGU7IH07XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18uZChnZXR0ZXIsICdhJywgZ2V0dGVyKTtcbiBcdFx0cmV0dXJuIGdldHRlcjtcbiBcdH07XG5cbiBcdC8vIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbFxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5vID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkgeyByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpOyB9O1xuXG4gXHQvLyBfX3dlYnBhY2tfcHVibGljX3BhdGhfX1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXCJcIjtcblxuXG4gXHQvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbiBcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IFwiLi9wcmV2aWV3LXNyYy9wcmUudHNcIik7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3Qgc2V0dGluZ3NfMSA9IHJlcXVpcmUoXCIuL3NldHRpbmdzXCIpO1xuY29uc3Qgc3RyaW5nc18xID0gcmVxdWlyZShcIi4vc3RyaW5nc1wiKTtcbi8qKlxuICogU2hvd3MgYW4gYWxlcnQgd2hlbiB0aGVyZSBpcyBhIGNvbnRlbnQgc2VjdXJpdHkgcG9saWN5IHZpb2xhdGlvbi5cbiAqL1xuY2xhc3MgQ3NwQWxlcnRlciB7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHRoaXMuZGlkU2hvdyA9IGZhbHNlO1xuICAgICAgICB0aGlzLmRpZEhhdmVDc3BXYXJuaW5nID0gZmFsc2U7XG4gICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3NlY3VyaXR5cG9saWN5dmlvbGF0aW9uJywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5vbkNzcFdhcm5pbmcoKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICBpZiAoZXZlbnQgJiYgZXZlbnQuZGF0YSAmJiBldmVudC5kYXRhLm5hbWUgPT09ICd2c2NvZGUtZGlkLWJsb2NrLXN2ZycpIHtcbiAgICAgICAgICAgICAgICB0aGlzLm9uQ3NwV2FybmluZygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgc2V0UG9zdGVyKHBvc3Rlcikge1xuICAgICAgICB0aGlzLm1lc3NhZ2luZyA9IHBvc3RlcjtcbiAgICAgICAgaWYgKHRoaXMuZGlkSGF2ZUNzcFdhcm5pbmcpIHtcbiAgICAgICAgICAgIHRoaXMuc2hvd0NzcFdhcm5pbmcoKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBvbkNzcFdhcm5pbmcoKSB7XG4gICAgICAgIHRoaXMuZGlkSGF2ZUNzcFdhcm5pbmcgPSB0cnVlO1xuICAgICAgICB0aGlzLnNob3dDc3BXYXJuaW5nKCk7XG4gICAgfVxuICAgIHNob3dDc3BXYXJuaW5nKCkge1xuICAgICAgICBjb25zdCBzdHJpbmdzID0gc3RyaW5nc18xLmdldFN0cmluZ3MoKTtcbiAgICAgICAgY29uc3Qgc2V0dGluZ3MgPSBzZXR0aW5nc18xLmdldFNldHRpbmdzKCk7XG4gICAgICAgIGlmICh0aGlzLmRpZFNob3cgfHwgc2V0dGluZ3MuZGlzYWJsZVNlY3VyaXR5V2FybmluZ3MgfHwgIXRoaXMubWVzc2FnaW5nKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kaWRTaG93ID0gdHJ1ZTtcbiAgICAgICAgY29uc3Qgbm90aWZpY2F0aW9uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYScpO1xuICAgICAgICBub3RpZmljYXRpb24uaW5uZXJUZXh0ID0gc3RyaW5ncy5jc3BBbGVydE1lc3NhZ2VUZXh0O1xuICAgICAgICBub3RpZmljYXRpb24uc2V0QXR0cmlidXRlKCdpZCcsICdjb2RlLWNzcC13YXJuaW5nJyk7XG4gICAgICAgIG5vdGlmaWNhdGlvbi5zZXRBdHRyaWJ1dGUoJ3RpdGxlJywgc3RyaW5ncy5jc3BBbGVydE1lc3NhZ2VUaXRsZSk7XG4gICAgICAgIG5vdGlmaWNhdGlvbi5zZXRBdHRyaWJ1dGUoJ3JvbGUnLCAnYnV0dG9uJyk7XG4gICAgICAgIG5vdGlmaWNhdGlvbi5zZXRBdHRyaWJ1dGUoJ2FyaWEtbGFiZWwnLCBzdHJpbmdzLmNzcEFsZXJ0TWVzc2FnZUxhYmVsKTtcbiAgICAgICAgbm90aWZpY2F0aW9uLm9uY2xpY2sgPSAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2luZy5wb3N0TWVzc2FnZSgnc2hvd1ByZXZpZXdTZWN1cml0eVNlbGVjdG9yJywgeyBzb3VyY2U6IHNldHRpbmdzLnNvdXJjZSB9KTtcbiAgICAgICAgfTtcbiAgICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChub3RpZmljYXRpb24pO1xuICAgIH1cbn1cbmV4cG9ydHMuQ3NwQWxlcnRlciA9IENzcEFsZXJ0ZXI7XG4iLCJcInVzZSBzdHJpY3RcIjtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmNsYXNzIFN0eWxlTG9hZGluZ01vbml0b3Ige1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLnVubG9hZGVkU3R5bGVzID0gW107XG4gICAgICAgIHRoaXMuZmluaXNoZWRMb2FkaW5nID0gZmFsc2U7XG4gICAgICAgIGNvbnN0IG9uU3R5bGVMb2FkRXJyb3IgPSAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHNvdXJjZSA9IGV2ZW50LnRhcmdldC5kYXRhc2V0LnNvdXJjZTtcbiAgICAgICAgICAgIHRoaXMudW5sb2FkZWRTdHlsZXMucHVzaChzb3VyY2UpO1xuICAgICAgICB9O1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignRE9NQ29udGVudExvYWRlZCcsICgpID0+IHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgbGluayBvZiBkb2N1bWVudC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKCdjb2RlLXVzZXItc3R5bGUnKSkge1xuICAgICAgICAgICAgICAgIGlmIChsaW5rLmRhdGFzZXQuc291cmNlKSB7XG4gICAgICAgICAgICAgICAgICAgIGxpbmsub25lcnJvciA9IG9uU3R5bGVMb2FkRXJyb3I7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCAoKSA9PiB7XG4gICAgICAgICAgICBpZiAoIXRoaXMudW5sb2FkZWRTdHlsZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5maW5pc2hlZExvYWRpbmcgPSB0cnVlO1xuICAgICAgICAgICAgaWYgKHRoaXMucG9zdGVyKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5wb3N0ZXIucG9zdE1lc3NhZ2UoJ3ByZXZpZXdTdHlsZUxvYWRFcnJvcicsIHsgdW5sb2FkZWRTdHlsZXM6IHRoaXMudW5sb2FkZWRTdHlsZXMgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBzZXRQb3N0ZXIocG9zdGVyKSB7XG4gICAgICAgIHRoaXMucG9zdGVyID0gcG9zdGVyO1xuICAgICAgICBpZiAodGhpcy5maW5pc2hlZExvYWRpbmcpIHtcbiAgICAgICAgICAgIHBvc3Rlci5wb3N0TWVzc2FnZSgncHJldmlld1N0eWxlTG9hZEVycm9yJywgeyB1bmxvYWRlZFN0eWxlczogdGhpcy51bmxvYWRlZFN0eWxlcyB9KTtcbiAgICAgICAgfVxuICAgIH1cbn1cbmV4cG9ydHMuU3R5bGVMb2FkaW5nTW9uaXRvciA9IFN0eWxlTG9hZGluZ01vbml0b3I7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3QgY3NwXzEgPSByZXF1aXJlKFwiLi9jc3BcIik7XG5jb25zdCBsb2FkaW5nXzEgPSByZXF1aXJlKFwiLi9sb2FkaW5nXCIpO1xud2luZG93LmNzcEFsZXJ0ZXIgPSBuZXcgY3NwXzEuQ3NwQWxlcnRlcigpO1xud2luZG93LnN0eWxlTG9hZGluZ01vbml0b3IgPSBuZXcgbG9hZGluZ18xLlN0eWxlTG9hZGluZ01vbml0b3IoKTtcbiIsIlwidXNlIHN0cmljdFwiO1xuLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5sZXQgY2FjaGVkU2V0dGluZ3MgPSB1bmRlZmluZWQ7XG5mdW5jdGlvbiBnZXREYXRhKGtleSkge1xuICAgIGNvbnN0IGVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndnNjb2RlLW1hcmtkb3duLXByZXZpZXctZGF0YScpO1xuICAgIGlmIChlbGVtZW50KSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBlbGVtZW50LmdldEF0dHJpYnV0ZShrZXkpO1xuICAgICAgICBpZiAoZGF0YSkge1xuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGF0YSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKGBDb3VsZCBub3QgbG9hZCBkYXRhIGZvciAke2tleX1gKTtcbn1cbmV4cG9ydHMuZ2V0RGF0YSA9IGdldERhdGE7XG5mdW5jdGlvbiBnZXRTZXR0aW5ncygpIHtcbiAgICBpZiAoY2FjaGVkU2V0dGluZ3MpIHtcbiAgICAgICAgcmV0dXJuIGNhY2hlZFNldHRpbmdzO1xuICAgIH1cbiAgICBjYWNoZWRTZXR0aW5ncyA9IGdldERhdGEoJ2RhdGEtc2V0dGluZ3MnKTtcbiAgICBpZiAoY2FjaGVkU2V0dGluZ3MpIHtcbiAgICAgICAgcmV0dXJuIGNhY2hlZFNldHRpbmdzO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCBsb2FkIHNldHRpbmdzJyk7XG59XG5leHBvcnRzLmdldFNldHRpbmdzID0gZ2V0U2V0dGluZ3M7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZnVuY3Rpb24gZ2V0U3RyaW5ncygpIHtcbiAgICBjb25zdCBzdG9yZSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2c2NvZGUtbWFya2Rvd24tcHJldmlldy1kYXRhJyk7XG4gICAgaWYgKHN0b3JlKSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBzdG9yZS5nZXRBdHRyaWJ1dGUoJ2RhdGEtc3RyaW5ncycpO1xuICAgICAgICBpZiAoZGF0YSkge1xuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGF0YSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKCdDb3VsZCBub3QgbG9hZCBzdHJpbmdzJyk7XG59XG5leHBvcnRzLmdldFN0cmluZ3MgPSBnZXRTdHJpbmdzO1xuIl0sInNvdXJjZVJvb3QiOiIifQ== diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 77627aa57b..011d62399d 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -241,12 +241,6 @@ "description": "%markdown.preview.scrollPreviewWithEditor.desc%", "scope": "resource" }, - "markdown.preview.scrollPreviewWithEditorSelection": { - "type": "boolean", - "default": true, - "description": "%markdown.preview.scrollPreviewWithEditorSelection.desc%", - "deprecationMessage": "%markdown.preview.scrollPreviewWithEditorSelection.deprecationMessage%" - }, "markdown.preview.markEditorSelection": { "type": "boolean", "default": true, @@ -279,6 +273,20 @@ "%configuration.markdown.preview.openMarkdownLinks.inEditor%" ] }, + "markdown.links.openLocation": { + "type": "string", + "default": "currentGroup", + "description": "%configuration.markdown.links.openLocation.description%", + "scope": "resource", + "enum": [ + "currentGroup", + "beside" + ], + "enumDescriptions": [ + "%configuration.markdown.links.openLocation.currentGroup%", + "%configuration.markdown.links.openLocation.beside%" + ] + }, "markdown.trace": { "type": "string", "enum": [ diff --git a/extensions/markdown-language-features/package.nls.json b/extensions/markdown-language-features/package.nls.json index 7841caff81..fbbab99951 100644 --- a/extensions/markdown-language-features/package.nls.json +++ b/extensions/markdown-language-features/package.nls.json @@ -10,8 +10,6 @@ "markdown.preview.markEditorSelection.desc": "Mark the current editor selection in the markdown preview.", "markdown.preview.scrollEditorWithPreview.desc": "When a markdown preview is scrolled, update the view of the editor.", "markdown.preview.scrollPreviewWithEditor.desc": "When a markdown editor is scrolled, update the view of the preview.", - "markdown.preview.scrollPreviewWithEditorSelection.desc": "[Deprecated] Scrolls the markdown preview to reveal the currently selected line from the editor.", - "markdown.preview.scrollPreviewWithEditorSelection.deprecationMessage": "This setting has been replaced by 'markdown.preview.scrollPreviewWithEditor' and no longer has any effect.", "markdown.preview.title": "Open Preview", "markdown.previewSide.title": "Open Preview to the Side", "markdown.showLockedPreviewToSide.title": "Open Locked Preview to the Side", @@ -21,7 +19,10 @@ "markdown.trace.desc": "Enable debug logging for the markdown extension.", "markdown.preview.refresh.title": "Refresh Preview", "markdown.preview.toggleLock.title": "Toggle Preview Locking", - "configuration.markdown.preview.openMarkdownLinks.description": "How should clicking on links to markdown files be handled in the preview.", + "configuration.markdown.preview.openMarkdownLinks.description": "Controls how links to other markdown files in the markdown preview should be opened.", "configuration.markdown.preview.openMarkdownLinks.inEditor": "Try to open links in the editor", - "configuration.markdown.preview.openMarkdownLinks.inPreview": "Try to open links in the markdown preview" -} \ No newline at end of file + "configuration.markdown.preview.openMarkdownLinks.inPreview": "Try to open links in the markdown preview", + "configuration.markdown.links.openLocation.description": "Controls where links in markdown files should be opened.", + "configuration.markdown.links.openLocation.currentGroup": "Open links in the active editor group.", + "configuration.markdown.links.openLocation.beside": "Open links beside the active editor." +} diff --git a/extensions/markdown-language-features/preview-src/tsconfig.json b/extensions/markdown-language-features/preview-src/tsconfig.json index 8a1e8a03fb..85159a000d 100644 --- a/extensions/markdown-language-features/preview-src/tsconfig.json +++ b/extensions/markdown-language-features/preview-src/tsconfig.json @@ -1,13 +1,7 @@ { + "extends": "../../shared.tsconfig.json", "compilerOptions": { "outDir": "./dist/", - "module": "commonjs", - "target": "es6", - "jsx": "react", - "sourceMap": true, - "strict": true, - "strictBindCallApply": true, - "noImplicitAny": true, - "noUnusedLocals": true + "jsx": "react" } -} \ No newline at end of file +} diff --git a/extensions/markdown-language-features/src/commands/openDocumentLink.ts b/extensions/markdown-language-features/src/commands/openDocumentLink.ts index 2760dce59b..53223f8e24 100644 --- a/extensions/markdown-language-features/src/commands/openDocumentLink.ts +++ b/extensions/markdown-language-features/src/commands/openDocumentLink.ts @@ -13,8 +13,14 @@ import { isMarkdownFile } from '../util/file'; export interface OpenDocumentLinkArgs { - path: string; - fragment: string; + readonly path: string; + readonly fragment: string; + readonly fromResource: any; +} + +enum OpenMarkdownLinks { + beside = 'beside', + currentGroup = 'currentGroup', } export class OpenDocumentLinkCommand implements Command { @@ -22,10 +28,15 @@ export class OpenDocumentLinkCommand implements Command { public readonly id = OpenDocumentLinkCommand.id; public static createCommandUri( + fromResource: vscode.Uri, path: string, - fragment: string + fragment: string, ): vscode.Uri { - return vscode.Uri.parse(`command:${OpenDocumentLinkCommand.id}?${encodeURIComponent(JSON.stringify({ path: encodeURIComponent(path), fragment }))}`); + return vscode.Uri.parse(`command:${OpenDocumentLinkCommand.id}?${encodeURIComponent(JSON.stringify({ + path: encodeURIComponent(path), + fragment, + fromResource: encodeURIComponent(fromResource.toString(true)), + }))}`); } public constructor( @@ -33,30 +44,45 @@ export class OpenDocumentLinkCommand implements Command { ) { } public execute(args: OpenDocumentLinkArgs) { - const p = decodeURIComponent(args.path); - return this.tryOpen(p, args).catch(() => { - if (p && extname(p) === '') { - return this.tryOpen(p + '.md', args); + const fromResource = vscode.Uri.parse(decodeURIComponent(args.fromResource)); + const targetPath = decodeURIComponent(args.path); + const column = this.getViewColumn(fromResource); + return this.tryOpen(targetPath, args, column).catch(() => { + if (targetPath && extname(targetPath) === '') { + return this.tryOpen(targetPath + '.md', args, column); } - const resource = vscode.Uri.file(p); + const targetResource = vscode.Uri.file(targetPath); return Promise.resolve(undefined) - .then(() => vscode.commands.executeCommand('vscode.open', resource)) + .then(() => vscode.commands.executeCommand('vscode.open', targetResource, column)) .then(() => undefined); }); } - private async tryOpen(path: string, args: OpenDocumentLinkArgs) { + private async tryOpen(path: string, args: OpenDocumentLinkArgs, column: vscode.ViewColumn) { const resource = vscode.Uri.file(path); if (vscode.window.activeTextEditor && isMarkdownFile(vscode.window.activeTextEditor.document)) { if (!path || vscode.window.activeTextEditor.document.uri.fsPath === resource.fsPath) { return this.tryRevealLine(vscode.window.activeTextEditor, args.fragment); } } + return vscode.workspace.openTextDocument(resource) - .then(vscode.window.showTextDocument) + .then(document => vscode.window.showTextDocument(document, column)) .then(editor => this.tryRevealLine(editor, args.fragment)); } + private getViewColumn(resource: vscode.Uri): vscode.ViewColumn { + const config = vscode.workspace.getConfiguration('markdown', resource); + const openLinks = config.get('links.openLocation', OpenMarkdownLinks.currentGroup); + switch (openLinks) { + case OpenMarkdownLinks.beside: + return vscode.ViewColumn.Beside; + case OpenMarkdownLinks.currentGroup: + default: + return vscode.ViewColumn.Active; + } + } + private async tryRevealLine(editor: vscode.TextEditor, fragment?: string) { if (editor && fragment) { const toc = new TableOfContentsProvider(this.engine, editor.document); @@ -107,4 +133,4 @@ async function tryResolveLinkToMarkdownFile(path: string): Promise { + this._registerDoc(doc); + }) + ); + this._register( + vscode.workspace.onDidCloseTextDocument((doc) => { + this._unregisterDoc(doc.uri); + }) + ); + } + + getByUri(uri: vscode.Uri): vscode.TextDocument | undefined { + return this._uriMap.get(uri.toString()); + } + + private _registerDoc(doc: vscode.TextDocument) { + const uri = doc.uri.toString(); + if (this._uriMap.has(uri)) { + throw new Error(`The document ${uri} is already registered.`); + } + this._uriMap.set(uri, doc); + } + + private _unregisterDoc(uri: vscode.Uri) { + if (!this._uriMap.has(uri.toString())) { + throw new Error(`The document ${uri.toString()} is not registered.`); + } + this._uriMap.delete(uri.toString()); + } +} diff --git a/extensions/markdown-language-features/src/features/documentLinkProvider.ts b/extensions/markdown-language-features/src/features/documentLinkProvider.ts index c36cfc03c2..4554ad03f9 100644 --- a/extensions/markdown-language-features/src/features/documentLinkProvider.ts +++ b/extensions/markdown-language-features/src/features/documentLinkProvider.ts @@ -38,7 +38,7 @@ function parseLink( } return { - uri: OpenDocumentLinkCommand.createCommandUri(resourcePath, tempUri.fragment), + uri: OpenDocumentLinkCommand.createCommandUri(document.uri, resourcePath, tempUri.fragment), tooltip: localize('documentLink.tooltip', 'Follow link') }; } @@ -183,4 +183,4 @@ export default class LinkProvider implements vscode.DocumentLinkProvider { } return out; } -} \ No newline at end of file +} diff --git a/extensions/markdown-language-features/src/features/preview.ts b/extensions/markdown-language-features/src/features/preview.ts index d0c3ba3d61..9b9719fe16 100644 --- a/extensions/markdown-language-features/src/features/preview.ts +++ b/extensions/markdown-language-features/src/features/preview.ts @@ -140,9 +140,9 @@ export class MarkdownPreview extends Disposable { MarkdownPreview.viewType, MarkdownPreview.getPreviewTitle(resource, locked), previewColumn, { - enableFindWidget: true, - ...MarkdownPreview.getWebviewOptions(resource, contributionProvider.contributions) - }); + enableFindWidget: true, + ...MarkdownPreview.getWebviewOptions(resource, contributionProvider.contributions) + }); return new MarkdownPreview( webview, @@ -288,12 +288,15 @@ export class MarkdownPreview extends Disposable { const editor = vscode.window.activeTextEditor; // Reposition scroll preview, position scroll to the top if active text editor // doesn't corresponds with preview - if (editor && editor.document.uri.fsPath === resource.fsPath) { - this.line = getVisibleLine(editor); - } else { - this.line = 0; + if (editor) { + if (editor.document.uri.fsPath === resource.fsPath) { + this.line = getVisibleLine(editor); + } else { + this.line = 0; + } } + // If we have changed resources, cancel any pending updates const isResourceChange = resource.fsPath !== this._resource.fsPath; if (isResourceChange) { @@ -540,7 +543,7 @@ export class MarkdownPreview extends Disposable { } } - vscode.commands.executeCommand('_markdown.openDocumentLink', { path, fragment }); + vscode.commands.executeCommand('_markdown.openDocumentLink', { path, fragment, fromResource: this.resource }); } private async onCacheImageSizes(imageInfo: { id: string, width: number, height: number }[]) { diff --git a/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts b/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts index 459eb3f7fd..6a5ab7af9f 100644 --- a/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts +++ b/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts @@ -8,8 +8,9 @@ import { Disposable } from '../util/dispose'; import { isMarkdownFile } from '../util/file'; import { Lazy, lazy } from '../util/lazy'; import MDDocumentSymbolProvider from './documentSymbolProvider'; -import { SkinnyTextDocument } from '../tableOfContentsProvider'; +import { SkinnyTextDocument, SkinnyTextLine } from '../tableOfContentsProvider'; import { flatten } from '../util/arrays'; +import { DocumentIndex } from '../docIndex'; export interface WorkspaceMarkdownDocumentProvider { getAllMarkdownDocuments(): Thenable>; @@ -26,6 +27,7 @@ class VSCodeWorkspaceMarkdownDocumentProvider extends Disposable implements Work private readonly _onDidDeleteMarkdownDocumentEmitter = this._register(new vscode.EventEmitter()); private _watcher: vscode.FileSystemWatcher | undefined; + private _docIndex: DocumentIndex = this._register(new DocumentIndex()); async getAllMarkdownDocuments() { const resources = await vscode.workspace.findFiles('**/*.md', '**/node_modules/**'); @@ -81,12 +83,39 @@ class VSCodeWorkspaceMarkdownDocumentProvider extends Disposable implements Work } private async getMarkdownDocument(resource: vscode.Uri): Promise { - const doc = await vscode.workspace.openTextDocument(resource); - return doc && isMarkdownFile(doc) ? doc : undefined; + const existingDocument = this._docIndex.getByUri(resource); + if (existingDocument) { + return existingDocument; + } + + const bytes = await vscode.workspace.fs.readFile(resource); + + // We assume that markdown is in UTF-8 + const text = Buffer.from(bytes).toString('utf-8'); + + const lines: SkinnyTextLine[] = []; + const parts = text.split(/(\r?\n)/); + const lineCount = Math.floor(parts.length / 2) + 1; + for (let line = 0; line < lineCount; line++) { + lines.push({ + text: parts[line * 2] + }); + } + + return { + uri: resource, + version: 0, + lineCount: lineCount, + lineAt: (index) => { + return lines[index]; + }, + getText: () => { + return text; + } + }; } } - export default class MarkdownWorkspaceSymbolProvider extends Disposable implements vscode.WorkspaceSymbolProvider { private _symbolCache = new Map>>(); private _symbolCachePopulated: boolean = false; diff --git a/extensions/markdown-language-features/src/security.ts b/extensions/markdown-language-features/src/security.ts index caacf60254..b309c3fa78 100644 --- a/extensions/markdown-language-features/src/security.ts +++ b/extensions/markdown-language-features/src/security.ts @@ -134,10 +134,10 @@ export class PreviewSecuritySelector { description: localize('toggleSecurityWarning.description', 'Does not affect the content security level') }, ], { - placeHolder: localize( - 'preview.showPreviewSecuritySelector.title', - 'Select security settings for Markdown previews in this workspace'), - }); + placeHolder: localize( + 'preview.showPreviewSecuritySelector.title', + 'Select security settings for Markdown previews in this workspace'), + }); if (!selection) { return; } diff --git a/extensions/markdown-language-features/src/tableOfContentsProvider.ts b/extensions/markdown-language-features/src/tableOfContentsProvider.ts index c24331ef02..3fc4023d24 100644 --- a/extensions/markdown-language-features/src/tableOfContentsProvider.ts +++ b/extensions/markdown-language-features/src/tableOfContentsProvider.ts @@ -15,12 +15,17 @@ export interface TocEntry { readonly location: vscode.Location; } +export interface SkinnyTextLine { + text: string; +} + export interface SkinnyTextDocument { readonly uri: vscode.Uri; readonly version: number; readonly lineCount: number; + + lineAt(line: number): SkinnyTextLine; getText(): string; - lineAt(line: number): vscode.TextLine; } export class TableOfContentsProvider { @@ -72,7 +77,8 @@ export class TableOfContentsProvider { text: TableOfContentsProvider.getHeaderText(line.text), level: TableOfContentsProvider.getHeaderLevel(heading.markup), line: lineNumber, - location: new vscode.Location(document.uri, line.range) + location: new vscode.Location(document.uri, + new vscode.Range(lineNumber, 0, lineNumber, line.text.length)) }); } @@ -85,13 +91,13 @@ export class TableOfContentsProvider { break; } } - const endLine = typeof end === 'number' ? end : document.lineCount - 1; + const endLine = end !== undefined ? end : document.lineCount - 1; return { ...entry, location: new vscode.Location(document.uri, new vscode.Range( entry.location.range.start, - new vscode.Position(endLine, document.lineAt(endLine).range.end.character))) + new vscode.Position(endLine, document.lineAt(endLine).text.length))) }; }); } diff --git a/extensions/mssql/src/config.json b/extensions/mssql/config.json similarity index 100% rename from extensions/mssql/src/config.json rename to extensions/mssql/config.json diff --git a/extensions/mssql/src/credentialstore/credentialstore.ts b/extensions/mssql/src/credentialstore/credentialstore.ts index 9d0d83d8dc..95b48d2f85 100644 --- a/extensions/mssql/src/credentialstore/credentialstore.ts +++ b/extensions/mssql/src/credentialstore/credentialstore.ts @@ -41,7 +41,7 @@ class CredentialsFeature extends SqlOpsFeature { const client = this._client; let readCredential = (credentialId: string): Thenable => { - return client.sendRequest(Contracts.ReadCredentialRequest.type, { credentialId }); + return client.sendRequest(Contracts.ReadCredentialRequest.type, { credentialId, password: undefined }); }; let saveCredential = (credentialId: string, password: string): Thenable => { @@ -49,7 +49,7 @@ class CredentialsFeature extends SqlOpsFeature { }; let deleteCredential = (credentialId: string): Thenable => { - return client.sendRequest(Contracts.DeleteCredentialRequest.type, { credentialId }); + return client.sendRequest(Contracts.DeleteCredentialRequest.type, { credentialId, password: undefined }); }; return azdata.credentials.registerProvider({ diff --git a/extensions/mssql/src/resourceProvider/resourceProvider.ts b/extensions/mssql/src/resourceProvider/resourceProvider.ts index 10e99a77d4..d7bb2d5396 100644 --- a/extensions/mssql/src/resourceProvider/resourceProvider.ts +++ b/extensions/mssql/src/resourceProvider/resourceProvider.ts @@ -55,9 +55,9 @@ class FireWallFeature extends SqlOpsFeature { } }, { - handleFirewallRule, - createFirewallRule - }); + handleFirewallRule, + createFirewallRule + }); } } diff --git a/extensions/mssql/src/sqlToolsServer.ts b/extensions/mssql/src/sqlToolsServer.ts index e5a4505277..ad3ad967a4 100644 --- a/extensions/mssql/src/sqlToolsServer.ts +++ b/extensions/mssql/src/sqlToolsServer.ts @@ -20,8 +20,8 @@ import { AppContext } from './appContext'; import { DacFxService } from './dacfx/dacFxService'; import { CmsService } from './cms/cmsService'; import { CompletionExtensionParams, CompletionExtLoadRequest } from './contracts'; - -const baseConfig = require('./config.json'); +import { promisify } from 'util'; +import { readFile } from 'fs'; const outputChannel = vscode.window.createOutputChannel(Constants.serviceName); const statusView = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); @@ -35,7 +35,7 @@ export class SqlToolsServer { public async start(context: AppContext): Promise { try { const installationStart = Date.now(); - const path = await this.download(); + const path = await this.download(context); const installationComplete = Date.now(); let serverOptions = generateServerOptions(context.extensionContext.logPath, path); let clientOptions = getClientOptions(context); @@ -69,8 +69,9 @@ export class SqlToolsServer { } } - private download() { - this.config = JSON.parse(JSON.stringify(baseConfig)); + private async download(context: AppContext): Promise { + const rawConfig = await promisify(readFile)(path.join(context.extensionContext.extensionPath, 'config.json')); + this.config = JSON.parse(rawConfig.toString()); this.config.installDirectory = path.join(__dirname, this.config.installDirectory); this.config.proxy = vscode.workspace.getConfiguration('http').get('proxy'); this.config.strictSSL = vscode.workspace.getConfiguration('http').get('proxyStrictSSL') || true; diff --git a/extensions/package.json b/extensions/package.json index 5c73fcbd3d..cbdafd7231 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "3.6.1-rc" + "typescript": "3.6.3-insiders.20190909" }, "scripts": { "postinstall": "node ./postinstall" diff --git a/extensions/powershell/cgmanifest.json b/extensions/powershell/cgmanifest.json index c8dcfd7cc8..04444f3617 100644 --- a/extensions/powershell/cgmanifest.json +++ b/extensions/powershell/cgmanifest.json @@ -14,4 +14,4 @@ } ], "version": 1 -} +} \ No newline at end of file diff --git a/extensions/schema-compare/package.json b/extensions/schema-compare/package.json index 645f16d6c1..bc3e8d6543 100644 --- a/extensions/schema-compare/package.json +++ b/extensions/schema-compare/package.json @@ -64,7 +64,7 @@ }, "devDependencies": { "@types/mocha": "^5.2.5", - "@types/node": "^8.0.24", + "@types/node": "^10.14.8", "mocha": "^5.2.0", "should": "^13.2.1", "typemoq": "^2.1.0", diff --git a/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts b/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts index 247fb23f92..cfd2ddc419 100644 --- a/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts +++ b/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts @@ -273,9 +273,9 @@ export class SchemaCompareDialog { components: targetComponents } ], { - horizontal: true, - titleFontSize: titleFontSize - }) + horizontal: true, + titleFontSize: titleFontSize + }) .withLayout({ width: '100%', padding: '10px 10px 0 30px' diff --git a/extensions/schema-compare/yarn.lock b/extensions/schema-compare/yarn.lock index 15a493ff04..cc782620cd 100644 --- a/extensions/schema-compare/yarn.lock +++ b/extensions/schema-compare/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.6.tgz#b8622d50557dd155e9f2f634b7d68fd38de5e94b" integrity sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw== -"@types/node@^8.0.24": - version "8.10.46" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.46.tgz#12161db48a775e8c69c1cfff2be545610381056f" - integrity sha512-PfnRbk836fFs9T9QnZh0G1k9oC6YXCqIK3LX6vU/6oiXtEBSFCiJFj6UnLZtqIIHTsgMn8Dojq3yhmpwY7QWcw== +"@types/node@^10.14.8": + version "10.14.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.17.tgz#b96d4dd3e427382482848948041d3754d40fd5ce" + integrity sha512-p/sGgiPaathCfOtqu2fx5Mu1bcjuP8ALFg4xpGgNkcin7LwRyzUKniEHBKdcE1RPsenq5JVPIpMTJSygLboygQ== ajv@^6.5.5: version "6.10.0" diff --git a/extensions/theme-abyss/themes/abyss-color-theme.json b/extensions/theme-abyss/themes/abyss-color-theme.json index 43a3ae648d..18c8235f79 100644 --- a/extensions/theme-abyss/themes/abyss-color-theme.json +++ b/extensions/theme-abyss/themes/abyss-color-theme.json @@ -358,6 +358,10 @@ "diffEditor.removedTextBackground": "#892F4688", // "diffEditor.removedTextBorder": "", + + // Editor: Minimap + "minimap.selectionHighlight": "#750000", + // Workbench: Title "titleBar.activeBackground": "#10192c", // "titleBar.activeForeground": "", @@ -439,4 +443,4 @@ "terminal.ansiBrightCyan": "#78ffff", "terminal.ansiBrightWhite": "#ffffff" } -} \ No newline at end of file +} diff --git a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json index 4b0eb5bdfc..d3a76435f6 100644 --- a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json +++ b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json @@ -17,6 +17,7 @@ "inputOption.activeBorder": "#a57a4c", "selection.background": "#84613daa", "editor.selectionBackground": "#84613daa", + "minimap.selectionHighlight": "#84613daa", "editorWidget.background": "#131510", "editorHoverWidget.background": "#221a14", "editorGroupHeader.tabsBackground": "#131510", @@ -398,4 +399,4 @@ } } ] -} \ No newline at end of file +} diff --git a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json index 5f5e5cff91..0a5851352b 100644 --- a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json +++ b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json @@ -11,6 +11,7 @@ "editor.background": "#1e1e1e", "editor.foreground": "#c5c8c6", "editor.selectionBackground": "#676b7180", + "minimap.selectionHighlight": "#676b7180", "editor.selectionHighlightBackground": "#575b6180", "editor.lineHighlightBackground": "#303030", "editorLineNumber.activeForeground": "#949494", @@ -588,4 +589,4 @@ } } ] -} \ No newline at end of file +} diff --git a/extensions/theme-monokai/themes/monokai-color-theme.json b/extensions/theme-monokai/themes/monokai-color-theme.json index c16fa3c557..ebff3a4498 100644 --- a/extensions/theme-monokai/themes/monokai-color-theme.json +++ b/extensions/theme-monokai/themes/monokai-color-theme.json @@ -23,6 +23,7 @@ "selection.background": "#ccccc7", "editor.selectionHighlightBackground": "#575b6180", "editor.selectionBackground": "#878b9180", + "minimap.selectionHighlight": "#878b9180", "editor.wordHighlightBackground": "#4a4a7680", "editor.wordHighlightStrongBackground": "#6a6a9680", "editor.lineHighlightBackground": "#3e3d32", diff --git a/extensions/theme-quietlight/themes/quietlight-color-theme.json b/extensions/theme-quietlight/themes/quietlight-color-theme.json index 38681612b4..355924fea2 100644 --- a/extensions/theme-quietlight/themes/quietlight-color-theme.json +++ b/extensions/theme-quietlight/themes/quietlight-color-theme.json @@ -499,6 +499,7 @@ "editor.lineHighlightBackground": "#E4F6D4", "editorLineNumber.activeForeground": "#9769dc", "editor.selectionBackground": "#C9D0D9", + "minimap.selectionHighlight": "#C9D0D9", "tab.modifiedBorder": "#f1897f", "panel.background": "#F5F5F5", "sideBar.background": "#F2F2F2", @@ -534,6 +535,8 @@ "errorForeground": "#f1897f", "badge.background": "#705697AA", "progressBar.background": "#705697", - "walkThrough.embeddedEditorBackground": "#00000014" + "walkThrough.embeddedEditorBackground": "#00000014", + "editorIndentGuide.background": "#aaaaaa60", + "editorIndentGuide.activeBackground": "#777777b0" } } diff --git a/extensions/theme-red/themes/Red-color-theme.json b/extensions/theme-red/themes/Red-color-theme.json index 18e5786a8f..309a4273fb 100644 --- a/extensions/theme-red/themes/Red-color-theme.json +++ b/extensions/theme-red/themes/Red-color-theme.json @@ -21,6 +21,7 @@ "editor.foreground": "#F8F8F8", "editorWhitespace.foreground": "#c10000", "editor.selectionBackground": "#750000", + "minimap.selectionHighlight": "#750000", "editorLineNumber.foreground": "#ff777788", "editorLineNumber.activeForeground": "#ffbbbb88", "editorWidget.background": "#300000", @@ -411,4 +412,4 @@ } } ] -} \ No newline at end of file +} diff --git a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json index f2ee483bea..0d6851d531 100644 --- a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json +++ b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json @@ -359,6 +359,7 @@ "editor.lineHighlightBackground": "#073642", "editorLineNumber.activeForeground": "#949494", "editor.selectionBackground": "#274642", + "minimap.selectionHighlight": "#274642", "editorIndentGuide.background": "#93A1A180", "editorIndentGuide.activeBackground": "#C3E1E180", "editorHoverWidget.background": "#004052", diff --git a/extensions/theme-solarized-light/themes/solarized-light-color-theme.json b/extensions/theme-solarized-light/themes/solarized-light-color-theme.json index 8cc7e74a77..b7020f8e7c 100644 --- a/extensions/theme-solarized-light/themes/solarized-light-color-theme.json +++ b/extensions/theme-solarized-light/themes/solarized-light-color-theme.json @@ -350,6 +350,7 @@ "editorWhitespace.foreground": "#586E7580", "editor.lineHighlightBackground": "#EEE8D5", "editor.selectionBackground": "#EEE8D5", + "minimap.selectionHighlight": "#EEE8D5", "editorIndentGuide.background": "#586E7580", "editorIndentGuide.activeBackground": "#081E2580", "editorHoverWidget.background": "#CCC4B0", @@ -486,4 +487,4 @@ // Interactive Playground "walkThrough.embeddedEditorBackground": "#00000014" } -} \ No newline at end of file +} diff --git a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json index 6c985d1ea5..f8c47a29e7 100644 --- a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json +++ b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json @@ -14,6 +14,7 @@ "editor.background": "#002451", "editor.foreground": "#ffffff", "editor.selectionBackground": "#003f8e", + "minimap.selectionHighlight": "#003f8e", "editor.lineHighlightBackground": "#00346e", "editorLineNumber.activeForeground": "#949494", "editorCursor.foreground": "#ffffff", @@ -255,4 +256,4 @@ } } ] -} \ No newline at end of file +} diff --git a/extensions/vscode-test-resolver/src/extension.ts b/extensions/vscode-test-resolver/src/extension.ts index 2716770fba..0910e5e1f7 100644 --- a/extensions/vscode-test-resolver/src/extension.ts +++ b/extensions/vscode-test-resolver/src/extension.ts @@ -78,7 +78,6 @@ export function activate(context: vscode.ExtensionContext) { } const { updateUrl, commit, quality, serverDataFolderName, dataFolderName } = getProductConfiguration(); - const serverCommand = process.platform === 'win32' ? 'server.bat' : 'server.sh'; const commandArgs = ['--port=0', '--disable-telemetry']; const env = getNewEnv(); const remoteDataDir = process.env['TESTRESOLVER_DATA_FOLDER'] || path.join(os.homedir(), serverDataFolderName || `${dataFolderName}-testresolver`); @@ -86,13 +85,19 @@ export function activate(context: vscode.ExtensionContext) { outputChannel.appendLine(`Using data folder at ${remoteDataDir}`); if (!commit) { // dev mode + const serverCommand = process.platform === 'win32' ? 'server.bat' : 'server.sh'; const vscodePath = path.resolve(path.join(context.extensionPath, '..', '..')); const serverCommandPath = path.join(vscodePath, 'resources', 'server', 'bin-dev', serverCommand); extHostProcess = cp.spawn(serverCommandPath, commandArgs, { env, cwd: vscodePath }); } else { - const serverBin = path.join(remoteDataDir, 'bin'); - progress.report({ message: 'Installing VSCode Server' }); - const serverLocation = await downloadAndUnzipVSCodeServer(updateUrl, commit, quality, serverBin); + const serverCommand = process.platform === 'win32' ? 'server.cmd' : 'server.sh'; + let serverLocation = env['VSCODE_REMOTE_SERVER_PATH']; // support environment variable to specify location of server on disk + if (!serverLocation) { + const serverBin = path.join(remoteDataDir, 'bin'); + progress.report({ message: 'Installing VSCode Server' }); + serverLocation = await downloadAndUnzipVSCodeServer(updateUrl, commit, quality, serverBin); + } + outputChannel.appendLine(`Using server build at ${serverLocation}`); extHostProcess = cp.spawn(path.join(serverLocation, serverCommand), commandArgs, { env, cwd: serverLocation }); diff --git a/extensions/yarn.lock b/extensions/yarn.lock index 26979cdf9d..f6ffdca517 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -typescript@3.6.1-rc: - version "3.6.1-rc" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.1-rc.tgz#9db650b25d8ef033d9e25b3057bdd1e102bb434b" - integrity sha512-u6AQN9AoocZKYSz8zcc1Qh/V/mbAO+BHc73fTiKlIdjzU60A8TesrK9/7kg3GM8o2RxNyCeOFpcevEtnfUyaLg== +typescript@3.6.3-insiders.20190909: + version "3.6.3-insiders.20190909" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.3-insiders.20190909.tgz#65b6b2d809288311a970819849e1964ac73e1fda" + integrity sha512-Lr7ONd8Y05EhrI+zKoI5tgvO5dhuRDrK5pyOLG33DeMln8zb8w7Yc8AoIEyqvxB5Btj9F7zBmXBXJdTI3SuX0Q== diff --git a/package.json b/package.json index 31df54991a..926d64b723 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "keytar": "^4.11.0", "native-is-elevated": "0.3.0", "native-keymap": "2.0.0", - "native-watchdog": "1.0.0", + "native-watchdog": "1.2.0", "ng2-charts": "^1.6.0", "node-pty": "0.9.0-beta19", "nsfw": "1.2.5", @@ -74,12 +74,12 @@ "vscode-chokidar": "2.1.7", "vscode-minimist": "^1.2.1", "vscode-proxy-agent": "0.4.0", - "vscode-ripgrep": "^1.5.6", + "vscode-ripgrep": "^1.5.7", "vscode-sqlite3": "4.0.8", "vscode-textmate": "^4.2.2", - "xterm": "3.15.0-beta101", - "xterm-addon-search": "0.2.0-beta5", - "xterm-addon-web-links": "0.1.0-beta10", + "xterm": "4.0.0", + "xterm-addon-search": "0.2.0", + "xterm-addon-web-links": "0.2.0", "yauzl": "^2.9.2", "yazl": "^2.4.3", "zone.js": "^0.8.4" @@ -107,8 +107,6 @@ "cson-parser": "^1.3.3", "debounce": "^1.0.0", "documentdb": "^1.5.1", - "electron-mksnapshot": "~2.0.0", - "eslint": "^4.18.2", "event-stream": "3.3.4", "express": "^4.13.1", "fancy-log": "^1.3.3", @@ -130,13 +128,10 @@ "gulp-rename": "^1.2.0", "gulp-replace": "^0.5.4", "gulp-shell": "^0.6.5", - "gulp-tsb": "2.0.7", + "gulp-tsb": "4.0.2", "gulp-tslint": "^8.1.3", - "gulp-uglify": "^3.0.0", "gulp-untar": "^0.0.7", "gulp-vinyl-zip": "^2.1.2", - "http-server": "^0.11.1", - "husky": "^0.13.1", "innosetup": "5.6.1", "is": "^3.1.0", "istanbul-lib-coverage": "^2.0.5", @@ -152,11 +147,10 @@ "mkdirp": "^0.5.0", "mocha": "^2.2.5", "mocha-junit-reporter": "^1.17.0", - "opn": "^5.4.0", + "opn": "^6.0.0", "optimist": "0.3.5", "p-all": "^1.0.0", "pump": "^1.0.1", - "puppeteer": "^1.19.0", "queue": "3.0.6", "rcedit": "^1.1.0", "rimraf": "^2.2.8", @@ -168,16 +162,15 @@ "tslint": "^5.16.0", "tslint-microsoft-contrib": "^6.0.0", "typemoq": "^0.3.2", - "typescript": "3.5.2", + "typescript": "3.6", "typescript-formatter": "7.1.0", - "uglify-es": "^3.0.18", "vinyl": "^2.0.0", "vinyl-fs": "^3.0.0", "vsce": "1.48.0", - "vscode-debugprotocol": "1.36.0-pre.0", + "vscode-debugprotocol": "1.36.0", "vscode-nls-dev": "^3.3.1", "webpack": "^4.16.5", - "webpack-cli": "^3.1.0", + "webpack-cli": "^3.3.8", "webpack-stream": "^5.1.1" }, "repository": { diff --git a/remote/package.json b/remote/package.json index 9fa3881681..0d57945f25 100644 --- a/remote/package.json +++ b/remote/package.json @@ -4,13 +4,13 @@ "dependencies": { "@microsoft/applicationinsights-web": "^2.1.1", "applicationinsights": "1.0.8", - "getmac": "1.4.1", + "cookie": "^0.4.0", "graceful-fs": "4.1.11", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.1", "iconv-lite": "0.5.0", "jschardet": "1.6.0", - "native-watchdog": "1.0.0", + "native-watchdog": "1.2.0", "node-pty": "0.9.0-beta19", "nsfw": "1.2.5", "onigasm-umd": "^2.2.2", @@ -19,11 +19,11 @@ "vscode-chokidar": "2.1.7", "vscode-minimist": "^1.2.1", "vscode-proxy-agent": "0.4.0", - "vscode-ripgrep": "^1.5.6", + "vscode-ripgrep": "^1.5.7", "vscode-textmate": "^4.2.2", - "xterm": "3.15.0-beta101", - "xterm-addon-search": "0.2.0-beta5", - "xterm-addon-web-links": "0.1.0-beta10", + "xterm": "4.0.0", + "xterm-addon-search": "0.2.0", + "xterm-addon-web-links": "0.2.0", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index f54afe1a3e..d488944039 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -2,12 +2,12 @@ "name": "vscode-web", "version": "0.0.0", "dependencies": { - "@microsoft/applicationinsights-web": "^2.1.1", - "onigasm-umd": "^2.2.2", - "vscode-textmate": "^4.1.1", - "xterm": "3.15.0-beta67", - "xterm-addon-search": "0.2.0-beta2", - "xterm-addon-web-links": "0.1.0-beta10", - "semver-umd": "^5.5.3" + "@microsoft/applicationinsights-web": "^2.1.1", + "onigasm-umd": "^2.2.2", + "semver-umd": "^5.5.3", + "vscode-textmate": "^4.2.2", + "xterm": "4.0.0", + "xterm-addon-search": "0.2.0", + "xterm-addon-web-links": "0.2.0" } - } \ No newline at end of file +} diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 23ad784a55..7b0ddab9d1 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -92,24 +92,24 @@ tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== -vscode-textmate@^4.1.1: +vscode-textmate@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.2.2.tgz#0b4dabc69a6fba79a065cb6b615f66eac07c8f4c" integrity sha512-1U4ih0E/KP1zNK/EbpUqyYtI7PY+Ccd2nDGTtiMR/UalLFnmaYkwoWhN1oI7B91ptBN8NdVwWuvyUnvJAulCUw== dependencies: oniguruma "^7.2.0" -xterm-addon-search@0.2.0-beta2: - version "0.2.0-beta2" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta2.tgz#c3173f0a6f207ee9f1848849174ee5d6b6ce8262" - integrity sha512-XEcwi2TeFGk2MuIFjiI/OpVXSNO5dGQBvHH3o+9KzqG3ooVqhhDqzwxs092QGNcNCGh8hGn/PWZiczaBBnKm/g== +xterm-addon-search@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0.tgz#46659c7c33f9fc268ad3e7e6c5824bb2fdb65852" + integrity sha512-C/v2VvFn3hb1qUgjJPo7LxzxNCLBgNJv8n6v/bH2NqPz32/PNUF+IHu0SFf1TaIH+pydUpKXCtob5a/UyZg/+Q== -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-addon-web-links@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.0.tgz#b408a0be46211d8d4a0bb5e701d8f3c2bd07d473" + integrity sha512-dq81c4Pzli2PgKVBgY2REte9sCVibR3df8AP3SEvCTM9uYFnUFxtxzMTplPnc7+rXabVhFdbU6x+rstIk8HNQg== -xterm@3.15.0-beta67: - version "3.15.0-beta67" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta67.tgz#71973e174bdc08df620945eecd3f87912f1ac550" - integrity sha512-qLfo9GHVlu/IxgDI3vRGObWZM7UL4eLhMfjZhprx2aXNMpzmrOW6l3JDRsCjUWm93EoVavbULtnDhGSiTlKitQ== +xterm@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.0.0.tgz#eac93e08cbe69cf238cbace9185ed9e38873df1a" + integrity sha512-Xbx3vvf9FnrUcI1qU31Jww7/fc/NqpXGqgByTvjj7+g3/yPvt/RvLkP/LLMcof2kLAC3evzZGMiovs7NkjdWDw== diff --git a/remote/yarn.lock b/remote/yarn.lock index 308bf9634b..6a545c7829 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -207,6 +207,11 @@ component-emitter@^1.2.1: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== +cookie@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" @@ -270,34 +275,6 @@ diagnostic-channel@0.2.0: dependencies: semver "^5.3.0" -eachr@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/eachr/-/eachr-3.2.0.tgz#2c35e43ea086516f7997cf80b7aa64d55a4a4484" - integrity sha1-LDXkPqCGUW95l8+At6pk1VpKRIQ= - dependencies: - editions "^1.1.1" - typechecker "^4.3.0" - -editions@^1.1.1, editions@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" - integrity sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg== - -editions@^2.1.0, editions@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/editions/-/editions-2.1.3.tgz#727ccf3ec2c7b12dcc652c71000f16c4824d6f7d" - integrity sha512-xDZyVm0A4nLgMNWVVLJvcwMjI80ShiH/27RyLiCnW1L273TcJIA25C4pwJ33AWV01OX6UriP35Xu+lH4S7HWQw== - dependencies: - errlop "^1.1.1" - semver "^5.6.0" - -errlop@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/errlop/-/errlop-1.1.1.tgz#d9ae4c76c3e64956c5d79e6e035d6343bfd62250" - integrity sha512-WX7QjiPHhsny7/PQvrhS5VMizXXKoKCS3udaBp8gjlARdbn+XmK300eKBAAN0hGyRaTCtRpOaxK+xFVPUJ3zkw== - dependencies: - editions "^2.1.2" - es6-promise@^4.0.3: version "4.2.4" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" @@ -352,15 +329,6 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-opts@^3.2.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/extract-opts/-/extract-opts-3.3.1.tgz#5abbedc98c0d5202e3278727f9192d7e086c6be1" - integrity sha1-WrvtyYwNUgLjJ4cn+Rktfghsa+E= - dependencies: - eachr "^3.2.0" - editions "^1.1.1" - typechecker "^4.3.0" - fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -409,14 +377,6 @@ get-value@^2.0.3, get-value@^2.0.6: resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= -getmac@1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/getmac/-/getmac-1.4.1.tgz#cfefcb3ee7d7a73cba5292129cb100c19afbe17a" - integrity sha512-mQp+8D+grQX0gG8EJn6VfH0PxE56ZKNsTguOMxPShAiVk9lvH8Ey36eXepG705Ac1HCsvaSrQ/6bPHZ0++F/Mg== - dependencies: - editions "^1.3.4" - extract-opts "^3.2.0" - glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -765,10 +725,10 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -native-watchdog@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/native-watchdog/-/native-watchdog-1.0.0.tgz#97344e83cd6815a8c8e6c44a52e7be05832e65ca" - integrity sha512-HKQATz5KLUMPyQQ/QaalzgTXaGz2plYPBxjyalaR4ECIu/UznXY8YJD+a9SLkkcvtxnJ8/zHLY3xik06vUZ7uA== +native-watchdog@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/native-watchdog/-/native-watchdog-1.2.0.tgz#9c710093ac6e9e60b19517cb1ef4ac9d7c997395" + integrity sha512-jOOoA3PLSxt1adaeuEW7ymV9cApZiDxn4y4iFs7b4sP73EG+5Lsz+OgUNFcGMyrtznTw6ZvlLcilIN4jeAIgaQ== node-addon-api@1.6.2: version "1.6.2" @@ -944,11 +904,6 @@ semver@^5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== -semver@^5.6.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" - integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== - set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" @@ -1092,13 +1047,6 @@ tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== -typechecker@^4.3.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/typechecker/-/typechecker-4.7.0.tgz#5249f427358f45b7250c4924fd4d01ed9ba435e9" - integrity sha512-4LHc1KMNJ6NDGO+dSM/yNfZQRtp8NN7psYrPHUblD62Dvkwsp3VShsbM78kOgpcmMkRTgvwdKOTjctS+uMllgQ== - dependencies: - editions "^2.1.0" - union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" @@ -1191,10 +1139,10 @@ vscode-proxy-agent@0.4.0: https-proxy-agent "2.2.1" socks-proxy-agent "4.0.1" -vscode-ripgrep@^1.5.6: - version "1.5.6" - resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.6.tgz#93bf5c99ca5f8248950a305e224f6ca153c30af4" - integrity sha512-WRIM9XpUj6dsfdAmuI3ANbmT1ysPUVsYy/2uCLDHJa9kbiB4T7uGvFnnc0Rgx2qQnyRAwL7PeWaFgUljPPxf2g== +vscode-ripgrep@^1.5.7: + version "1.5.7" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.7.tgz#acb6b548af488a4bca5d0f1bb5faf761343289ce" + integrity sha512-/Vsz/+k8kTvui0q3O74pif9FK0nKopgFTiGNVvxicZANxtSA8J8gUE9GQ/4dpi7D/2yI/YVORszwVskFbz46hQ== vscode-textmate@^4.2.2: version "4.2.2" @@ -1215,20 +1163,20 @@ vscode-windows-registry@1.0.2: resolved "https://registry.yarnpkg.com/vscode-windows-registry/-/vscode-windows-registry-1.0.2.tgz#b863e704a6a69c50b3098a55fbddbe595b0c124a" integrity sha512-/CLLvuOSM2Vme2z6aNyB+4Omd7hDxpf4Thrt8ImxnXeQtxzel2bClJpFQvQqK/s4oaXlkBKS7LqVLeZM+uSVIA== -xterm-addon-search@0.2.0-beta5: - version "0.2.0-beta5" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta5.tgz#258d7cb1511d9060cd4520f0f82e408000fd4f53" - integrity sha512-Tg+d8scch0rYOVmzBbX35Y1GXtq+eu/YlzbXznmTo/yD83j3BQlXOhgECu/Yv8EX5JwFmzbfVRWC+JWnfigwGg== +xterm-addon-search@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0.tgz#46659c7c33f9fc268ad3e7e6c5824bb2fdb65852" + integrity sha512-C/v2VvFn3hb1qUgjJPo7LxzxNCLBgNJv8n6v/bH2NqPz32/PNUF+IHu0SFf1TaIH+pydUpKXCtob5a/UyZg/+Q== -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-addon-web-links@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.0.tgz#b408a0be46211d8d4a0bb5e701d8f3c2bd07d473" + integrity sha512-dq81c4Pzli2PgKVBgY2REte9sCVibR3df8AP3SEvCTM9uYFnUFxtxzMTplPnc7+rXabVhFdbU6x+rstIk8HNQg== -xterm@3.15.0-beta101: - version "3.15.0-beta101" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta101.tgz#38ffa0df5a3e9bdcb1818e74fe59b2f98b0fff69" - integrity sha512-HRa7+FDqQ8iWBTvb1Ni+uMGILnu6k9mF7JHMHRHfWxFoQlSoGYCyfdyXlJjk68YN8GsEQREmrII6cPLiQizdEQ== +xterm@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.0.0.tgz#eac93e08cbe69cf238cbace9185ed9e38873df1a" + integrity sha512-Xbx3vvf9FnrUcI1qU31Jww7/fc/NqpXGqgByTvjj7+g3/yPvt/RvLkP/LLMcof2kLAC3evzZGMiovs7NkjdWDw== yauzl@^2.9.2: version "2.10.0" diff --git a/resources/linux/bin/code.sh b/resources/linux/bin/code.sh index 32f19a7c99..0cf035d2ad 100755 --- a/resources/linux/bin/code.sh +++ b/resources/linux/bin/code.sh @@ -4,7 +4,7 @@ # Licensed under the Source EULA. See License.txt in the project root for license information. # test that VSCode wasn't installed inside WSL -if grep -qi Microsoft /proc/version; then +if grep -qi Microsoft /proc/version && [ -z "$DONT_PROMPT_WSL_INSTALL" ]; then echo "To use VS Code with the Windows Subsystem for Linux, please install VS Code in Windows and uninstall the Linux version in WSL. You can then use the '@@PRODNAME@@' command in a WSL terminal just as you would in a normal command prompt." 1>&2 read -e -p "Do you want to continue anyways ? [y/N] " YN diff --git a/resources/linux/code-url-handler.desktop b/resources/linux/code-url-handler.desktop index ef9a634e14..b8e921920b 100644 --- a/resources/linux/code-url-handler.desktop +++ b/resources/linux/code-url-handler.desktop @@ -2,7 +2,7 @@ Name=@@NAME_LONG@@ - URL Handler Comment=Azure Data Studio GenericName=Text Editor -Exec=/usr/share/@@NAME@@/@@NAME@@ --open-url %U +Exec=@@EXEC@@ --open-url %U Icon=@@ICON@@ Type=Application NoDisplay=true diff --git a/resources/linux/code.desktop b/resources/linux/code.desktop index 8df4caec62..3940900ed6 100644 --- a/resources/linux/code.desktop +++ b/resources/linux/code.desktop @@ -2,7 +2,7 @@ Name=@@NAME_LONG@@ Comment=Data Management Tool that enables you to work with SQL Server, Azure SQL DB and SQL DW from Windows, macOS and Linux. GenericName=Text Editor -Exec=/usr/share/@@NAME@@/@@NAME@@ --unity-launch %F +Exec=@@EXEC@@ --unity-launch %F Icon=@@ICON@@ Type=Application StartupNotify=false @@ -14,5 +14,5 @@ Keywords=azuredatastudio; [Desktop Action new-empty-window] Name=New Empty Window -Exec=/usr/share/@@NAME@@/@@NAME@@ --new-window %F +Exec=@@EXEC@@ --new-window %F Icon=@@ICON@@ diff --git a/resources/linux/snap/snapcraft.yaml b/resources/linux/snap/snapcraft.yaml index d8616e4ae7..c39e5f4f84 100644 --- a/resources/linux/snap/snapcraft.yaml +++ b/resources/linux/snap/snapcraft.yaml @@ -50,7 +50,6 @@ parts: apps: @@NAME@@: command: electron-launch $SNAP/usr/share/@@NAME@@/bin/@@NAME@@ - desktop: usr/share/applications/@@NAME@@.desktop common-id: @@NAME@@.desktop environment: DISABLE_WAYLAND: 1 @@ -58,7 +57,6 @@ apps: url-handler: command: electron-launch $SNAP/usr/share/@@NAME@@/bin/@@NAME@@ --open-url - desktop: usr/share/applications/@@NAME@@-url-handler.desktop environment: DISABLE_WAYLAND: 1 GSETTINGS_SCHEMA_DIR: $SNAP/usr/share/glib-2.0/schemas diff --git a/resources/win32/bin/code.sh b/resources/win32/bin/code.sh index 71dc4a18c4..54f9429b7d 100644 --- a/resources/win32/bin/code.sh +++ b/resources/win32/bin/code.sh @@ -26,7 +26,7 @@ if grep -qi Microsoft /proc/version; then # use the Remote WSL extension if installed WSL_EXT_ID="ms-vscode-remote.remote-wsl" - if [ $WSL_BUILD -ge 41955 ]; then + if [ $WSL_BUILD -ge 41955 -a $WSL_BUILD -lt 41959 ]; then # WSL2 in workaround for https://github.com/microsoft/WSL/issues/4337 CWD="$(pwd)" cd "$VSCODE_PATH" diff --git a/scripts/code.sh b/scripts/code.sh index 542efab523..e82babd818 100755 --- a/scripts/code.sh +++ b/scripts/code.sh @@ -5,10 +5,6 @@ set -e if [[ "$OSTYPE" == "darwin"* ]]; then realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; } ROOT=$(dirname "$(dirname "$(realpath "$0")")") - - # On Linux with Electron 2.0.x running out of a VM causes - # a freeze so we only enable this flag on macOS - export ELECTRON_ENABLE_LOGGING=1 else ROOT=$(dirname "$(dirname "$(readlink -f $0)")") if grep -qi Microsoft /proc/version; then @@ -50,6 +46,8 @@ function code() { export VSCODE_DEV=1 export VSCODE_CLI=1 export ELECTRON_ENABLE_STACK_DUMPING=1 + export ELECTRON_ENABLE_LOGGING=1 + export VSCODE_LOGS= # Launch Code exec "$CODE" . "$@" diff --git a/scripts/test-release.bat b/scripts/test-documentation.bat similarity index 66% rename from scripts/test-release.bat rename to scripts/test-documentation.bat index cb9c3b205c..c6990f8f3f 100644 --- a/scripts/test-release.bat +++ b/scripts/test-documentation.bat @@ -1,6 +1,8 @@ @echo off setlocal +echo Runs tests against the current documentation in https://github.com/microsoft/vscode-docs/tree/vnext + pushd %~dp0\.. :: Endgame tests in AMD diff --git a/scripts/test-release.sh b/scripts/test-documentation.sh similarity index 79% rename from scripts/test-release.sh rename to scripts/test-documentation.sh index f7a0800dc9..54a0672945 100755 --- a/scripts/test-release.sh +++ b/scripts/test-documentation.sh @@ -12,6 +12,8 @@ fi cd $ROOT +echo "Runs tests against the current documentation in https://github.com/microsoft/vscode-docs/tree/vnext" + # Tests in AMD ./scripts/test.sh --runGlob **/*.releaseTest.js "$@" diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index 7d89aa1ab8..9a1e0b4565 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -5,28 +5,47 @@ pushd %~dp0\.. set VSCODEUSERDATADIR=%TMP%\vscodeuserfolder-%RANDOM%-%TIME:~6,5% +:: Figure out which Electron to use for running tests +if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" ( + :: Run out of sources: no need to compile as code.sh takes care of it + set INTEGRATION_TEST_ELECTRON_PATH=.\scripts\code.bat + + echo "Running integration tests out of sources." +) else ( + :: Run from a built: need to compile all test extensions + call yarn gulp compile-extension:vscode-api-tests + call yarn gulp compile-extension:vscode-colorize-tests + call yarn gulp compile-extension:markdown-language-features + call yarn gulp compile-extension:emmet + call yarn gulp compile-extension:css-language-features-server + call yarn gulp compile-extension:html-language-features-server + call yarn gulp compile-extension:json-language-features-server + + echo "Running integration tests with '%INTEGRATION_TEST_ELECTRON_PATH%' as build." +) + :: Integration & performance tests in AMD :: TODO port over an re-enable API tests :: call .\scripts\test.bat --runGlob **\*.integrationTest.js %* :: if %errorlevel% neq 0 exit /b %errorlevel% :: Tests in the extension host -call .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testWorkspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% if %errorlevel% neq 0 exit /b %errorlevel% -call .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% if %errorlevel% neq 0 exit /b %errorlevel% -call .\scripts\code.bat %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% -call .\scripts\code.bat %~dp0\..\extensions\markdown-language-features\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\markdown-language-features --extensionTestsPath=%~dp0\..\extensions\markdown-language-features\out\test --disableExtensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% -call .\scripts\code.bat %~dp0\..\extensions\azurecore\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\azurecore --extensionTestsPath=%~dp0\..\extensions\azurecore\out\test --disableExtensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\markdown-language-features\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\markdown-language-features --extensionTestsPath=%~dp0\..\extensions\markdown-language-features\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\azurecore\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\azurecore --extensionTestsPath=%~dp0\..\extensions\azurecore\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% if %errorlevel% neq 0 exit /b %errorlevel% -:: call .\scripts\code.bat $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% . +:: call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% :: if %errorlevel% neq 0 exit /b %errorlevel% -:: Integration & performance tests in AMD -call .\scripts\test.bat --runGlob **\*.integrationTest.js %* +:: call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% . +:: if %errorlevel% neq 0 exit /b %errorlevel% :: Tests in commonJS (HTML, CSS, JSON language server tests...) call .\scripts\node-electron.bat .\node_modules\mocha\bin\_mocha .\extensions\*\server\out\test\**\*.test.js diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index b2e3f755c1..9dd5449c32 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -12,21 +12,41 @@ fi cd $ROOT +# Figure out which Electron to use for running tests +if [ -z "$INTEGRATION_TEST_ELECTRON_PATH" ] +then + # Run out of sources: no need to compile as code.sh takes care of it + INTEGRATION_TEST_ELECTRON_PATH="./scripts/code.sh" + + echo "Running integration tests out of sources." +else + # Run from a built: need to compile all test extensions + yarn gulp compile-extension:vscode-api-tests + yarn gulp compile-extension:vscode-colorize-tests + yarn gulp compile-extension:markdown-language-features + yarn gulp compile-extension:emmet + yarn gulp compile-extension:css-language-features-server + yarn gulp compile-extension:html-language-features-server + yarn gulp compile-extension:json-language-features-server + + echo "Running integration tests with '$INTEGRATION_TEST_ELECTRON_PATH' as build." +fi + # Integration tests in AMD ./scripts/test.sh --runGlob **/*.integrationTest.js "$@" # Tests in the extension host -# TODO port over an re-enable API tests -#./scripts/code.sh $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR -#./scripts/code.sh $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR -./scripts/code.sh $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR -./scripts/code.sh $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR -./scripts/code.sh $ROOT/extensions/azurecore/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/azurecore --extensionTestsPath=$ROOT/extensions/azurecore/out/test --disableExtensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR +# "$INTEGRATION_TEST_ELECTRON_PATH" $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR +# "$INTEGRATION_TEST_ELECTRON_PATH" $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $ROOT/extensions/azurecore/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/azurecore --extensionTestsPath=$ROOT/extensions/azurecore/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR mkdir -p $ROOT/extensions/emmet/test-fixtures -./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR rm -rf $ROOT/extensions/emmet/test-fixtures +# Remote Integration Tests if [ -f ./resources/server/test/test-remote-integration.sh ]; then ./resources/server/test/test-remote-integration.sh fi diff --git a/scripts/test.bat b/scripts/test.bat index b1430b516e..941b21d156 100644 --- a/scripts/test.bat +++ b/scripts/test.bat @@ -16,8 +16,8 @@ node build\lib\electron.js if %errorlevel% neq 0 node .\node_modules\gulp\bin\gulp.js electron :: Run tests - - %CODE% .\test\electron\index.js %* +set ELECTRON_ENABLE_LOGGING=1 +%CODE% .\test\electron\index.js %* popd diff --git a/scripts/test.sh b/scripts/test.sh index 8855f421ea..9b6a3b86b8 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -4,10 +4,6 @@ if [[ "$OSTYPE" == "darwin"* ]] || [[ "$AGENT_OS" == "Darwin"* ]]; then realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; } ROOT=$(dirname $(dirname $(realpath "$0"))) - - # On Linux with Electron 2.0.x running out of a VM causes - # a freeze so we only enable this flag on macOS - export ELECTRON_ENABLE_LOGGING=1 else ROOT=$(dirname $(dirname $(readlink -f $0))) fi @@ -31,10 +27,12 @@ node build/lib/electron.js || ./node_modules/.bin/gulp electron # Unit Tests if [[ "$OSTYPE" == "darwin"* ]] || [[ "$AGENT_OS" == "Darwin"* ]]; then cd $ROOT ; ulimit -n 4096 ; \ + ELECTRON_ENABLE_LOGGING=1 \ "$CODE" \ test/electron/index.js "$@" else cd $ROOT ; \ + ELECTRON_ENABLE_LOGGING=1 \ "$CODE" \ test/electron/index.js "$@" fi diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js index 0dae048aa4..cad91629bd 100644 --- a/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -34,7 +34,7 @@ exports.load = function (modulePaths, resultCallback, options) { * // configuration: IWindowConfiguration * @type {{ * zoomLevel?: number, - * extensionDevelopmentPath?: string | string[], + * extensionDevelopmentPath?: string[], * extensionTestsPath?: string, * userEnv?: { [key: string]: string | undefined }, * appRoot?: string, diff --git a/src/bootstrap.js b/src/bootstrap.js index 1e8a03ec6c..8d95ffee95 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -203,7 +203,7 @@ exports.setupNLS = function () { const bundles = Object.create(null); nlsConfig.loadBundle = function (bundle, language, cb) { - let result = bundles[bundle]; + const result = bundles[bundle]; if (result) { cb(undefined, result); @@ -212,7 +212,7 @@ exports.setupNLS = function () { const bundleFile = path.join(nlsConfig._resolvedLanguagePackCoreLocation, bundle.replace(/\//g, '!') + '.nls.json'); exports.readFile(bundleFile).then(function (content) { - let json = JSON.parse(content); + const json = JSON.parse(content); bundles[bundle] = json; cb(undefined, json); @@ -301,4 +301,4 @@ exports.avoidMonkeyPatchFromAppInsights = function () { process.env['APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL'] = true; // Skip monkey patching of 3rd party modules by appinsights global['diagnosticsSource'] = {}; // Prevents diagnostic channel (which patches "require") from initializing entirely }; -//#endregion \ No newline at end of file +//#endregion diff --git a/src/buildfile.js b/src/buildfile.js index 03da50adcd..06d0d59b83 100644 --- a/src/buildfile.js +++ b/src/buildfile.js @@ -15,18 +15,10 @@ exports.base = [{ dest: 'vs/base/worker/workerMain.js' }]; -exports.serviceWorker = [{ - name: 'vs/workbench/contrib/resources/browser/resourceServiceWorker', - // include: ['vs/editor/common/services/editorSimpleWorker'], - prepend: ['vs/loader.js'], - append: ['vs/workbench/contrib/resources/browser/resourceServiceWorkerMain'], - dest: 'vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.js' -}]; - exports.workerExtensionHost = [entrypoint('vs/workbench/services/extensions/worker/extensionHostWorker')]; -exports.workbench = require('./vs/workbench/buildfile').collectModules(['vs/workbench/workbench.desktop.main']); -exports.workbenchWeb = entrypoint('vs/workbench/workbench.web.api'); +exports.workbenchDesktop = require('./vs/workbench/buildfile.desktop').collectModules(); +exports.workbenchWeb = require('./vs/workbench/buildfile.web').collectModules(); exports.keyboardMaps = [ entrypoint('vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux'), diff --git a/src/sql/base/browser/ui/table/plugins/autoSizeColumns.plugin.ts b/src/sql/base/browser/ui/table/plugins/autoSizeColumns.plugin.ts index 36af00cdc0..6361a6dca0 100644 --- a/src/sql/base/browser/ui/table/plugins/autoSizeColumns.plugin.ts +++ b/src/sql/base/browser/ui/table/plugins/autoSizeColumns.plugin.ts @@ -100,7 +100,7 @@ export class AutoColumnSize implements Slick.Plugin { } } - private handleDoubleClick(e: JQuery.Event) { + private handleDoubleClick(e: JQuery.Event) { let headerEl = jQuery(e.currentTarget).closest('.slick-header-column'); let columnDef = headerEl.data('column'); diff --git a/src/sql/base/browser/ui/table/plugins/checkboxSelectColumn.plugin.ts b/src/sql/base/browser/ui/table/plugins/checkboxSelectColumn.plugin.ts index c3e76a1c19..a07b0072a7 100644 --- a/src/sql/base/browser/ui/table/plugins/checkboxSelectColumn.plugin.ts +++ b/src/sql/base/browser/ui/table/plugins/checkboxSelectColumn.plugin.ts @@ -92,7 +92,7 @@ export class CheckboxSelectColumn implements Slick.Pl delete this._selectedRowsLookup[row]; } } - dict.forEach(this._selectedRowsLookup, (e) => this._grid.invalidateRow(e.key)); + dict.forEach(this._selectedRowsLookup, (e) => this._grid.invalidateRow(Number(e.key))); this._selectedRowsLookup = lookup; this._grid.render(); diff --git a/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts b/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts index 48fc516849..c57880f632 100644 --- a/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts +++ b/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts @@ -6,6 +6,9 @@ import { localize } from 'vs/nls'; import { Button } from 'sql/base/browser/ui/button/button'; import { escape } from 'sql/base/common/strings'; +import { addDisposableListener } from 'vs/base/browser/dom'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { withNullAsUndefined } from 'vs/base/common/types'; interface IExtendedColumn extends Slick.Column { filterValues?: Array; @@ -27,6 +30,8 @@ export class HeaderFilter { private columnDef: IExtendedColumn; private buttonStyles: IButtonStyles; + private disposableStore = new DisposableStore(); + public init(grid: Slick.Grid): void { this.grid = grid; this.handler.subscribe(this.grid.onHeaderCellRendered, (e: Event, args: Slick.OnHeaderCellRenderedEventArgs) => this.handleHeaderCellRendered(e, args)) @@ -36,17 +41,16 @@ export class HeaderFilter { .subscribe(this.grid.onKeyDown, (e: KeyboardEvent) => this.handleKeyDown(e)); this.grid.setColumns(this.grid.getColumns()); - jQuery(document.body).bind('mousedown', this.handleBodyMouseDown); - jQuery(document.body).bind('keydown', this.handleKeyDown); + this.disposableStore.add(addDisposableListener(document.body, 'mousedown', e => this.handleBodyMouseDown(e))); + this.disposableStore.add(addDisposableListener(document.body, 'keydown', e => this.handleKeyDown(e))); } public destroy() { this.handler.unsubscribeAll(); - jQuery(document.body).unbind('mousedown', this.handleBodyMouseDown); - jQuery(document.body).unbind('keydown', this.handleKeyDown); + this.disposableStore.dispose(); } - private handleKeyDown(e: KeyboardEvent | JQuery.Event): void { + private handleKeyDown(e: KeyboardEvent): void { if (this.$menu && (e.key === 'Escape' || e.keyCode === 27)) { this.hideMenu(); e.preventDefault(); @@ -54,7 +58,7 @@ export class HeaderFilter { } } - private handleBodyMouseDown(e: MouseEvent | JQuery.Event): void { + private handleBodyMouseDown(e: MouseEvent): void { if (this.$menu && this.$menu[0] !== e.target && !jQuery.contains(this.$menu[0], e.target as Element)) { this.hideMenu(); e.preventDefault(); @@ -78,8 +82,8 @@ export class HeaderFilter { .addClass('slick-header-menubutton') .data('column', column); - $el.bind('click', (e) => this.showFilter(e)).appendTo(args.node); - $el.bind('keydown', (e) => { + $el.bind('click', (e: KeyboardEvent) => this.showFilter(e)).appendTo(args.node); + $el.bind('keydown', (e: KeyboardEvent) => { if (e.key === 'Enter' || e.keyCode === 13) { this.showFilter(e); } @@ -146,8 +150,9 @@ export class HeaderFilter { }); } - private showFilter(e: JQuery.Event) { - const $menuButton = jQuery(e.target); + private showFilter(e: KeyboardEvent) { + const target = withNullAsUndefined(e.target); + const $menuButton = jQuery(target); this.columnDef = $menuButton.data('column'); this.columnDef.filterValues = this.columnDef.filterValues || []; @@ -222,16 +227,16 @@ export class HeaderFilter { this.applyStyles(); jQuery(':checkbox', $filter).bind('click', (e) => { - this.workingFilters = this.changeWorkingFilter(filterItems, this.workingFilters, jQuery(e.target)); + this.workingFilters = this.changeWorkingFilter(filterItems, this.workingFilters, jQuery(target)); }); - const offset = jQuery(e.target).offset(); - const left = offset.left - this.$menu.width() + jQuery(e.target).width() - 8; + const offset = jQuery(target).offset(); + const left = offset.left - this.$menu.width() + jQuery(target).width() - 8; - let menutop = offset.top + jQuery(e.target).height(); + let menutop = offset.top + jQuery(target).height(); if (menutop + offset.top > jQuery(window).height()) { - menutop -= (this.$menu.height() + jQuery(e.target).height() + 8); + menutop -= (this.$menu.height() + jQuery(target).height() + 8); } this.$menu.css('top', menutop) .css('left', (left > 0 ? left : 0)); diff --git a/src/sql/platform/accounts/browser/accountDialog.ts b/src/sql/platform/accounts/browser/accountDialog.ts index 1ec472a70b..de8e3671b8 100644 --- a/src/sql/platform/accounts/browser/accountDialog.ts +++ b/src/sql/platform/accounts/browser/accountDialog.ts @@ -54,7 +54,7 @@ class AccountPanel extends ViewletPanel { } protected renderBody(container: HTMLElement): void { - this.accountList = new List(container, new AccountListDelegate(AccountDialog.ACCOUNTLIST_HEIGHT), [this.instantiationService.createInstance(AccountListRenderer)]); + this.accountList = new List('AccountList', container, new AccountListDelegate(AccountDialog.ACCOUNTLIST_HEIGHT), [this.instantiationService.createInstance(AccountListRenderer)]); this._register(attachListStyler(this.accountList, this.themeService)); } diff --git a/src/sql/platform/accounts/browser/accountPicker.ts b/src/sql/platform/accounts/browser/accountPicker.ts index 2e4e52ba1c..83d41a430c 100644 --- a/src/sql/platform/accounts/browser/accountPicker.ts +++ b/src/sql/platform/accounts/browser/accountPicker.ts @@ -10,7 +10,7 @@ import * as azdata from 'azdata'; export const IAccountPickerService = createDecorator('AccountPickerService'); export interface IAccountPickerService { - _serviceBrand: any; + _serviceBrand: undefined; renderAccountPicker(container: HTMLElement): void; addAccountCompleteEvent: Event; addAccountErrorEvent: Event; diff --git a/src/sql/platform/accounts/browser/accountPickerImpl.ts b/src/sql/platform/accounts/browser/accountPickerImpl.ts index 9beefe423e..9f6350207a 100644 --- a/src/sql/platform/accounts/browser/accountPickerImpl.ts +++ b/src/sql/platform/accounts/browser/accountPickerImpl.ts @@ -87,7 +87,7 @@ export class AccountPicker extends Disposable { const delegate = new AccountListDelegate(AccountPicker.ACCOUNTPICKERLIST_HEIGHT); const accountRenderer = new AccountPickerListRenderer(); this._listContainer = DOM.$('div.account-list-container'); - this._accountList = new List(this._listContainer, delegate, [accountRenderer]); + this._accountList = new List('AccountPicker', this._listContainer, delegate, [accountRenderer]); this._register(attachListStyler(this._accountList, this._themeService)); this._rootElement = DOM.$('div.account-picker-container'); diff --git a/src/sql/platform/accounts/browser/accountPickerService.ts b/src/sql/platform/accounts/browser/accountPickerService.ts index 0a37c64073..d92c7a2ad3 100644 --- a/src/sql/platform/accounts/browser/accountPickerService.ts +++ b/src/sql/platform/accounts/browser/accountPickerService.ts @@ -11,7 +11,7 @@ import { IAccountPickerService } from 'sql/platform/accounts/browser/accountPick import { AccountPicker } from 'sql/platform/accounts/browser/accountPickerImpl'; export class AccountPickerService implements IAccountPickerService { - _serviceBrand: any; + _serviceBrand: undefined; private _accountPicker: AccountPicker; diff --git a/src/sql/platform/accounts/common/interfaces.ts b/src/sql/platform/accounts/common/interfaces.ts index 72f4532e83..6122e6697c 100644 --- a/src/sql/platform/accounts/common/interfaces.ts +++ b/src/sql/platform/accounts/common/interfaces.ts @@ -13,7 +13,7 @@ export const SERVICE_ID = 'accountManagementService'; export const IAccountManagementService = createDecorator(SERVICE_ID); export interface IAccountManagementService { - _serviceBrand: any; + _serviceBrand: undefined; // ACCOUNT MANAGEMENT METHODS ////////////////////////////////////////// accountUpdated(account: azdata.Account): Thenable; diff --git a/src/sql/platform/accounts/test/common/testAccountManagementService.ts b/src/sql/platform/accounts/test/common/testAccountManagementService.ts index 498c891b6d..6a85684423 100644 --- a/src/sql/platform/accounts/test/common/testAccountManagementService.ts +++ b/src/sql/platform/accounts/test/common/testAccountManagementService.ts @@ -9,7 +9,7 @@ import { IAccountManagementService } from 'sql/platform/accounts/common/interfac import { AccountProviderAddedEventParams, UpdateAccountListEventParams } from 'sql/platform/accounts/common/eventTypes'; export class TestAccountManagementService implements IAccountManagementService { - _serviceBrand: any; + _serviceBrand: undefined; public get addAccountProviderEvent(): Event { return Event.None; } public get removeAccountProviderEvent(): Event { return Event.None; } diff --git a/src/sql/platform/angularEventing/common/angularEventingService.ts b/src/sql/platform/angularEventing/common/angularEventingService.ts index 25590b298d..cef43c04a0 100644 --- a/src/sql/platform/angularEventing/common/angularEventingService.ts +++ b/src/sql/platform/angularEventing/common/angularEventingService.ts @@ -29,7 +29,7 @@ export interface IAngularEvent { } export interface IAngularEventingService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Adds a listener for the dashboard to send events, should only be called once for each dashboard by the dashboard itself * @param uri Uri of the dashboard diff --git a/src/sql/platform/angularEventing/node/angularEventingService.ts b/src/sql/platform/angularEventing/node/angularEventingService.ts index bd0cb94cb4..33b1f15fb3 100644 --- a/src/sql/platform/angularEventing/node/angularEventingService.ts +++ b/src/sql/platform/angularEventing/node/angularEventingService.ts @@ -10,7 +10,7 @@ import { IAngularEventingService, IAngularEvent, AngularEventType } from 'sql/pl import { ILogService } from 'vs/platform/log/common/log'; export class AngularEventingService implements IAngularEventingService { - public _serviceBrand: any; + public _serviceBrand: undefined; private _angularMap = new Map>(); constructor( diff --git a/src/sql/platform/backup/common/backupService.ts b/src/sql/platform/backup/common/backupService.ts index dc5e816fe4..accd08321e 100644 --- a/src/sql/platform/backup/common/backupService.ts +++ b/src/sql/platform/backup/common/backupService.ts @@ -17,7 +17,7 @@ export const SERVICE_ID = 'backupService'; export const IBackupService = createDecorator(SERVICE_ID); export interface IBackupService { - _serviceBrand: any; + _serviceBrand: undefined; getBackupConfigInfo(connectionUri: string): Thenable; diff --git a/src/sql/platform/backup/common/backupServiceImp.ts b/src/sql/platform/backup/common/backupServiceImp.ts index c5c45b70f3..950c1ece7d 100644 --- a/src/sql/platform/backup/common/backupServiceImp.ts +++ b/src/sql/platform/backup/common/backupServiceImp.ts @@ -14,7 +14,7 @@ import { ILogService } from 'vs/platform/log/common/log'; export class BackupService implements IBackupService { - public _serviceBrand: any; + public _serviceBrand: undefined; private _providers: { [handle: string]: azdata.BackupProvider; } = Object.create(null); constructor( diff --git a/src/sql/platform/capabilities/common/capabilitiesService.ts b/src/sql/platform/capabilities/common/capabilitiesService.ts index acb00c2ecb..8794d61a74 100644 --- a/src/sql/platform/capabilities/common/capabilitiesService.ts +++ b/src/sql/platform/capabilities/common/capabilitiesService.ts @@ -30,7 +30,7 @@ export const ICapabilitiesService = createDecorator(SERVIC * Interface for managing provider capabilities */ export interface ICapabilitiesService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Retrieve a list of registered capabilities providers diff --git a/src/sql/platform/capabilities/common/capabilitiesServiceImpl.ts b/src/sql/platform/capabilities/common/capabilitiesServiceImpl.ts index c89c286ca6..cc03e96297 100644 --- a/src/sql/platform/capabilities/common/capabilitiesServiceImpl.ts +++ b/src/sql/platform/capabilities/common/capabilitiesServiceImpl.ts @@ -33,7 +33,7 @@ interface CapabilitiesMomento { * to discover the DMP capabilities that a DMP provider offers. */ export class CapabilitiesService extends Disposable implements ICapabilitiesService { - _serviceBrand: any; + _serviceBrand: undefined; private _momento: Memento; private _providers = new Map(); diff --git a/src/sql/platform/capabilities/test/common/testCapabilitiesService.ts b/src/sql/platform/capabilities/test/common/testCapabilitiesService.ts index f1b0f37c4b..e28ced142e 100644 --- a/src/sql/platform/capabilities/test/common/testCapabilitiesService.ts +++ b/src/sql/platform/capabilities/test/common/testCapabilitiesService.ts @@ -14,7 +14,7 @@ import { mssqlProviderName } from 'sql/platform/connection/common/constants'; export class TestCapabilitiesService implements ICapabilitiesService { - public _serviceBrand: any; + public _serviceBrand: undefined; public capabilities: { [id: string]: ProviderFeatures } = {}; diff --git a/src/sql/platform/clipboard/electron-browser/clipboardService.ts b/src/sql/platform/clipboard/electron-browser/clipboardService.ts index f252e858a1..6f2be7d970 100644 --- a/src/sql/platform/clipboard/electron-browser/clipboardService.ts +++ b/src/sql/platform/clipboard/electron-browser/clipboardService.ts @@ -9,7 +9,7 @@ import { BrowserClipboardService } from 'sql/platform/clipboard/browser/clipboar import { clipboard, nativeImage } from 'electron'; export class ClipboardService extends BrowserClipboardService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @vsIClipboardService _vsClipboardService: vsIClipboardService, diff --git a/src/sql/platform/connection/browser/connectionManagementService.ts b/src/sql/platform/connection/browser/connectionManagementService.ts index 7ee5c186de..ff28c352e9 100644 --- a/src/sql/platform/connection/browser/connectionManagementService.ts +++ b/src/sql/platform/connection/browser/connectionManagementService.ts @@ -53,7 +53,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati export class ConnectionManagementService extends Disposable implements IConnectionManagementService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private _providers = new Map, properties: ConnectionProviderProperties }>(); private _iconProviders = new Map(); diff --git a/src/sql/platform/connection/common/connectionManagement.ts b/src/sql/platform/connection/common/connectionManagement.ts index b016f78267..d6cdad47ac 100644 --- a/src/sql/platform/connection/common/connectionManagement.ts +++ b/src/sql/platform/connection/common/connectionManagement.ts @@ -65,7 +65,7 @@ export const SERVICE_ID = 'connectionManagementService'; export const IConnectionManagementService = createDecorator(SERVICE_ID); export interface IConnectionManagementService { - _serviceBrand: any; + _serviceBrand: undefined; // Event Emitters onAddConnectionProfile: Event; diff --git a/src/sql/platform/connection/test/common/testConfigurationService.ts b/src/sql/platform/connection/test/common/testConfigurationService.ts index e2e930d7a6..9dbe8b7960 100644 --- a/src/sql/platform/connection/test/common/testConfigurationService.ts +++ b/src/sql/platform/connection/test/common/testConfigurationService.ts @@ -6,7 +6,7 @@ import { getConfigurationKeys, IConfigurationOverrides, IConfigurationService, getConfigurationValue, isConfigurationOverrides, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export class TestConfigurationService implements IConfigurationService { - public _serviceBrand: any; + public _serviceBrand: undefined; private configuration = { user: {}, diff --git a/src/sql/platform/connection/test/common/testConnectionManagementService.ts b/src/sql/platform/connection/test/common/testConnectionManagementService.ts index 74449cab99..9a49a95a78 100644 --- a/src/sql/platform/connection/test/common/testConnectionManagementService.ts +++ b/src/sql/platform/connection/test/common/testConnectionManagementService.ts @@ -16,7 +16,7 @@ import { ConnectionProviderProperties } from 'sql/workbench/parts/connection/com // Test stubs for commonly used objects export class TestConnectionManagementService implements IConnectionManagementService { - _serviceBrand: any; + _serviceBrand: undefined; onAddConnectionProfile = undefined; onDeleteConnectionProfile = undefined; onConnectionChanged = undefined; diff --git a/src/sql/platform/credentials/common/credentialsService.ts b/src/sql/platform/credentials/common/credentialsService.ts index cdbbcdc118..3a7ff1d76e 100644 --- a/src/sql/platform/credentials/common/credentialsService.ts +++ b/src/sql/platform/credentials/common/credentialsService.ts @@ -21,7 +21,7 @@ export interface CredentialManagementEvents { export const ICredentialsService = createDecorator(SERVICE_ID); export interface ICredentialsService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; saveCredential(credentialId: string, password: string): Promise; @@ -34,7 +34,7 @@ export interface ICredentialsService { export class CredentialsService implements ICredentialsService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; private _serverEvents: { [handle: number]: CredentialManagementEvents; } = Object.create(null); diff --git a/src/sql/platform/credentials/test/common/testCredentialsService.ts b/src/sql/platform/credentials/test/common/testCredentialsService.ts index 017bb69965..4a767eb0f1 100644 --- a/src/sql/platform/credentials/test/common/testCredentialsService.ts +++ b/src/sql/platform/credentials/test/common/testCredentialsService.ts @@ -9,7 +9,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { Emitter } from 'vs/base/common/event'; export class TestCredentialsService implements ICredentialsService { - _serviceBrand: any; + _serviceBrand: undefined; public credentials = new Map(); diff --git a/src/sql/platform/dashboard/browser/dashboardService.ts b/src/sql/platform/dashboard/browser/dashboardService.ts index c35515ab40..fa73136a09 100644 --- a/src/sql/platform/dashboard/browser/dashboardService.ts +++ b/src/sql/platform/dashboard/browser/dashboardService.ts @@ -12,7 +12,7 @@ export const IDashboardService = createDecorator('dashboardSe export interface IDashboardService { - _serviceBrand: any; + _serviceBrand: undefined; readonly onDidOpenDashboard: Event; readonly onDidChangeToDashboard: Event; readonly onLayout: Event; diff --git a/src/sql/platform/dashboard/browser/dashboardServiceImpl.ts b/src/sql/platform/dashboard/browser/dashboardServiceImpl.ts index 6f7d2496ac..648367c23d 100644 --- a/src/sql/platform/dashboard/browser/dashboardServiceImpl.ts +++ b/src/sql/platform/dashboard/browser/dashboardServiceImpl.ts @@ -9,7 +9,7 @@ import * as DOM from 'vs/base/browser/dom'; import * as azdata from 'azdata'; export class DashboardService implements IDashboardService { - public _serviceBrand: any; + public _serviceBrand: undefined; private _onDidOpenDashboard = new Emitter(); public readonly onDidOpenDashboard: Event = this._onDidOpenDashboard.event; diff --git a/src/sql/platform/dashboard/browser/dashboardViewService.ts b/src/sql/platform/dashboard/browser/dashboardViewService.ts index e883349836..323b6c5bfc 100644 --- a/src/sql/platform/dashboard/browser/dashboardViewService.ts +++ b/src/sql/platform/dashboard/browser/dashboardViewService.ts @@ -17,7 +17,7 @@ export interface IDashboardWebview extends IView { } export interface IDashboardViewService { - _serviceBrand: any; + _serviceBrand: undefined; onRegisteredWebview: Event; registerWebview(widget: IDashboardWebview); onRegisteredModelView: Event; diff --git a/src/sql/platform/dashboard/browser/dashboardViewServiceImpl.ts b/src/sql/platform/dashboard/browser/dashboardViewServiceImpl.ts index ac84ee040a..b10b6c2b6f 100644 --- a/src/sql/platform/dashboard/browser/dashboardViewServiceImpl.ts +++ b/src/sql/platform/dashboard/browser/dashboardViewServiceImpl.ts @@ -8,7 +8,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IModelView } from 'sql/platform/model/browser/modelViewService'; export class DashboardViewService implements IDashboardViewService { - _serviceBrand: any; + _serviceBrand: undefined; private _onRegisteredWebview = new Emitter(); public readonly onRegisteredWebview: Event = this._onRegisteredWebview.event; diff --git a/src/sql/platform/errorMessage/common/errorMessageService.ts b/src/sql/platform/errorMessage/common/errorMessageService.ts index ef3d4b03cd..4fdaf06e75 100644 --- a/src/sql/platform/errorMessage/common/errorMessageService.ts +++ b/src/sql/platform/errorMessage/common/errorMessageService.ts @@ -9,6 +9,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export const IErrorMessageService = createDecorator('errorMessageService'); export interface IErrorMessageService { - _serviceBrand: any; + _serviceBrand: undefined; showDialog(severity: Severity, headerTitle: string, message: string, messageDetails?: string, actions?: IAction[]): void; } diff --git a/src/sql/platform/errorMessage/test/common/testErrorMessageService.ts b/src/sql/platform/errorMessage/test/common/testErrorMessageService.ts index 5fbd195310..03b22af96a 100644 --- a/src/sql/platform/errorMessage/test/common/testErrorMessageService.ts +++ b/src/sql/platform/errorMessage/test/common/testErrorMessageService.ts @@ -7,7 +7,7 @@ import Severity from 'vs/base/common/severity'; import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService'; export class TestErrorMessageService implements IErrorMessageService { - _serviceBrand: any; + _serviceBrand: undefined; showDialog(severity: Severity, headerTitle: string, message: string): void { } -} \ No newline at end of file +} diff --git a/src/sql/platform/fileBrowser/common/fileBrowserService.ts b/src/sql/platform/fileBrowser/common/fileBrowserService.ts index 0079beea48..adba04339e 100644 --- a/src/sql/platform/fileBrowser/common/fileBrowserService.ts +++ b/src/sql/platform/fileBrowser/common/fileBrowserService.ts @@ -17,7 +17,7 @@ import * as strings from 'vs/base/common/strings'; import { invalidProvider } from 'sql/base/common/errors'; export class FileBrowserService implements IFileBrowserService { - public _serviceBrand: any; + public _serviceBrand: undefined; private _providers: { [handle: string]: azdata.FileBrowserProvider; } = Object.create(null); private _onAddFileTree = new Emitter(); private _onExpandFolder = new Emitter(); diff --git a/src/sql/platform/fileBrowser/common/interfaces.ts b/src/sql/platform/fileBrowser/common/interfaces.ts index 49810747e9..874d558924 100644 --- a/src/sql/platform/fileBrowser/common/interfaces.ts +++ b/src/sql/platform/fileBrowser/common/interfaces.ts @@ -11,7 +11,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export const IFileBrowserService = createDecorator('fileBrowserService'); export interface IFileBrowserService { - _serviceBrand: any; + _serviceBrand: undefined; onAddFileTree: Event; onExpandFolder: Event; onPathValidate: Event; @@ -55,4 +55,4 @@ export interface IFileBrowserService { * Close file browser */ closeFileBrowser(ownerUri: string): Thenable; -} \ No newline at end of file +} diff --git a/src/sql/platform/jobManagement/common/interfaces.ts b/src/sql/platform/jobManagement/common/interfaces.ts index f9c115ad64..1833f9fa80 100644 --- a/src/sql/platform/jobManagement/common/interfaces.ts +++ b/src/sql/platform/jobManagement/common/interfaces.ts @@ -13,7 +13,7 @@ export const SERVICE_ID = 'jobManagementService'; export const IJobManagementService = createDecorator(SERVICE_ID); export interface IJobManagementService { - _serviceBrand: any; + _serviceBrand: undefined; onDidChange: Event; registerProvider(providerId: string, provider: azdata.AgentServicesProvider): void; diff --git a/src/sql/platform/jobManagement/common/jobManagementService.ts b/src/sql/platform/jobManagement/common/jobManagementService.ts index c091bf0cb6..1ad9aeff8a 100644 --- a/src/sql/platform/jobManagement/common/jobManagementService.ts +++ b/src/sql/platform/jobManagement/common/jobManagementService.ts @@ -10,7 +10,7 @@ import { IConnectionManagementService } from 'sql/platform/connection/common/con import { Event, Emitter } from 'vs/base/common/event'; export class JobManagementService implements IJobManagementService { - _serviceBrand: any; + _serviceBrand: undefined; private _onDidChange = new Emitter(); public readonly onDidChange: Event = this._onDidChange.event; @@ -213,7 +213,7 @@ export class JobManagementService implements IJobManagementService { * Server level caching of jobs/job histories and their views */ export class JobCacheObject { - _serviceBrand: any; + _serviceBrand: undefined; private _jobs: azdata.AgentJobInfo[] = []; private _jobHistories: { [jobID: string]: azdata.AgentJobHistoryInfo[]; } = {}; private _jobSteps: { [jobID: string]: azdata.AgentJobStepInfo[]; } = {}; @@ -399,7 +399,7 @@ export class NotebookCacheObject { * Server level caching of Operators */ export class OperatorsCacheObject { - _serviceBrand: any; + _serviceBrand: undefined; private _operators: azdata.AgentOperatorInfo[]; private _dataView: Slick.Data.DataView; private _serverName: string; @@ -436,7 +436,7 @@ export class OperatorsCacheObject { * Server level caching of job alerts and the alerts view */ export class AlertsCacheObject { - _serviceBrand: any; + _serviceBrand: undefined; private _alerts: azdata.AgentAlertInfo[]; private _dataView: Slick.Data.DataView; private _serverName: string; @@ -473,7 +473,7 @@ export class AlertsCacheObject { * Server level caching of job proxies and proxies view */ export class ProxiesCacheObject { - _serviceBrand: any; + _serviceBrand: undefined; private _proxies: azdata.AgentProxyInfo[]; private _dataView: Slick.Data.DataView; private _serverName: string; diff --git a/src/sql/platform/metadata/common/metadataService.ts b/src/sql/platform/metadata/common/metadataService.ts index 5370d98069..70f97f8fd6 100644 --- a/src/sql/platform/metadata/common/metadataService.ts +++ b/src/sql/platform/metadata/common/metadataService.ts @@ -12,7 +12,7 @@ export const SERVICE_ID = 'metadataService'; export const IMetadataService = createDecorator(SERVICE_ID); export interface IMetadataService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; getMetadata(connectionUri: string): Thenable; @@ -30,7 +30,7 @@ export interface IMetadataService { export class MetadataService implements IMetadataService { - public _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; private _providers: { [handle: string]: azdata.MetadataProvider; } = Object.create(null); diff --git a/src/sql/platform/modelComponents/browser/modelViewService.ts b/src/sql/platform/modelComponents/browser/modelViewService.ts index 1772f36662..f682408a63 100644 --- a/src/sql/platform/modelComponents/browser/modelViewService.ts +++ b/src/sql/platform/modelComponents/browser/modelViewService.ts @@ -11,7 +11,7 @@ import { IModelView } from 'sql/platform/model/browser/modelViewService'; export const SERVICE_ID = 'modelViewService'; export interface IModelViewService { - _serviceBrand: any; + _serviceBrand: undefined; onRegisteredModelView: Event; registerModelView(widget: IModelView); } diff --git a/src/sql/platform/modelComponents/browser/modelViewServiceImpl.ts b/src/sql/platform/modelComponents/browser/modelViewServiceImpl.ts index 7d00b1c819..66db189037 100644 --- a/src/sql/platform/modelComponents/browser/modelViewServiceImpl.ts +++ b/src/sql/platform/modelComponents/browser/modelViewServiceImpl.ts @@ -8,7 +8,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IModelView } from 'sql/platform/model/browser/modelViewService'; export class ModelViewService implements IModelViewService { - _serviceBrand: any; + _serviceBrand: undefined; private _onRegisteredModelView = new Emitter(); public readonly onRegisteredModelView: Event = this._onRegisteredModelView.event; diff --git a/src/sql/platform/oAuth/common/sqlOAuthService.ts b/src/sql/platform/oAuth/common/sqlOAuthService.ts index ce8321560b..466b3ae353 100644 --- a/src/sql/platform/oAuth/common/sqlOAuthService.ts +++ b/src/sql/platform/oAuth/common/sqlOAuthService.ts @@ -13,7 +13,7 @@ export const ISqlOAuthService = createDecorator('sqlOAuthServi * electron-based services are referenced in unit testable code. */ export interface ISqlOAuthService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Sends request to main thread to handle OAuth request diff --git a/src/sql/platform/oAuth/electron-browser/sqlOAuthServiceImpl.ts b/src/sql/platform/oAuth/electron-browser/sqlOAuthServiceImpl.ts index fbf534fe80..4045e57083 100644 --- a/src/sql/platform/oAuth/electron-browser/sqlOAuthServiceImpl.ts +++ b/src/sql/platform/oAuth/electron-browser/sqlOAuthServiceImpl.ts @@ -12,7 +12,7 @@ import { ISqlOAuthService } from 'sql/platform/oAuth/common/sqlOAuthService'; * electron-based services are referenced in unit testable code. */ export class SqlOAuthService implements ISqlOAuthService { - public _serviceBrand: any; + public _serviceBrand: undefined; /** * Sends request to main thread to handle OAuth request diff --git a/src/sql/platform/query/common/queryManagement.ts b/src/sql/platform/query/common/queryManagement.ts index ed2fb48e15..71c251009c 100644 --- a/src/sql/platform/query/common/queryManagement.ts +++ b/src/sql/platform/query/common/queryManagement.ts @@ -20,7 +20,7 @@ export const SERVICE_ID = 'queryManagementService'; export const IQueryManagementService = createDecorator(SERVICE_ID); export interface IQueryManagementService { - _serviceBrand: any; + _serviceBrand: undefined; onHandlerAdded: Event; @@ -91,7 +91,7 @@ export interface IQueryRequestHandler { } export class QueryManagementService implements IQueryManagementService { - public _serviceBrand: any; + public _serviceBrand: undefined; private _requestHandlers = new Map(); private _onHandlerAddedEmitter = new Emitter(); diff --git a/src/sql/platform/query/common/queryModel.ts b/src/sql/platform/query/common/queryModel.ts index b48ea016ca..d488f7607e 100644 --- a/src/sql/platform/query/common/queryModel.ts +++ b/src/sql/platform/query/common/queryModel.ts @@ -47,7 +47,7 @@ export interface IQueryEvent { * Interface for the logic of handling running queries and grid interactions for all URIs. */ export interface IQueryModelService { - _serviceBrand: any; + _serviceBrand: undefined; getQueryRunner(uri: string): QueryRunner; diff --git a/src/sql/platform/query/common/queryModelService.ts b/src/sql/platform/query/common/queryModelService.ts index 1a99856b7b..f7afe2df08 100644 --- a/src/sql/platform/query/common/queryModelService.ts +++ b/src/sql/platform/query/common/queryModelService.ts @@ -53,7 +53,7 @@ export class QueryInfo { * Handles running queries and grid interactions for all URIs. Interacts with each URI's results grid via a DataService instance */ export class QueryModelService implements IQueryModelService { - _serviceBrand: any; + _serviceBrand: undefined; // MEMBER VARIABLES //////////////////////////////////////////////////// private _queryInfoMap: Map; diff --git a/src/sql/platform/restore/browser/restoreServiceImpl.ts b/src/sql/platform/restore/browser/restoreServiceImpl.ts index 464dcccdb2..afec28b0d3 100644 --- a/src/sql/platform/restore/browser/restoreServiceImpl.ts +++ b/src/sql/platform/restore/browser/restoreServiceImpl.ts @@ -29,7 +29,7 @@ import { ILogService } from 'vs/platform/log/common/log'; export class RestoreService implements IRestoreService { - public _serviceBrand: any; + public _serviceBrand: undefined; private _providers: { [handle: string]: azdata.RestoreProvider; } = Object.create(null); constructor( @@ -132,7 +132,7 @@ export class RestoreService implements IRestoreService { } export class RestoreDialogController implements IRestoreDialogController { - _serviceBrand: any; + _serviceBrand: undefined; private _restoreDialogs: { [provider: string]: RestoreDialog | OptionsDialog } = {}; private _currentProvider: string; diff --git a/src/sql/platform/restore/common/restoreService.ts b/src/sql/platform/restore/common/restoreService.ts index 974ce1680c..bbea73c7ef 100644 --- a/src/sql/platform/restore/common/restoreService.ts +++ b/src/sql/platform/restore/common/restoreService.ts @@ -13,7 +13,7 @@ export const SERVICE_ID = 'restoreService'; export const IRestoreService = createDecorator(SERVICE_ID); export interface IRestoreService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Register a disaster recovery provider @@ -43,6 +43,6 @@ export interface IRestoreService { export const IRestoreDialogController = createDecorator('restoreDialogService'); export interface IRestoreDialogController { - _serviceBrand: any; + _serviceBrand: undefined; showDialog(connection: IConnectionProfile): Promise; } diff --git a/src/sql/platform/scripting/common/scriptingService.ts b/src/sql/platform/scripting/common/scriptingService.ts index b5eb134b58..f8e500e947 100644 --- a/src/sql/platform/scripting/common/scriptingService.ts +++ b/src/sql/platform/scripting/common/scriptingService.ts @@ -23,7 +23,7 @@ export enum ScriptOperation { } export interface IScriptingService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; script(connectionUri: string, metadata: azdata.ObjectMetadata, operation: ScriptOperation, paramDetails: azdata.ScriptingParamDetails): Thenable; @@ -50,7 +50,7 @@ export interface IScriptingService { export class ScriptingService implements IScriptingService { - public _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; private _providers: { [handle: string]: azdata.ScriptingProvider; } = Object.create(null); diff --git a/src/sql/platform/serialization/common/serializationService.ts b/src/sql/platform/serialization/common/serializationService.ts index a52be7ac75..8b2320868d 100644 --- a/src/sql/platform/serialization/common/serializationService.ts +++ b/src/sql/platform/serialization/common/serializationService.ts @@ -39,7 +39,7 @@ export interface SerializeDataParams { } export interface ISerializationService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; registerProvider(providerId: string, provider: azdata.SerializationProvider): void; @@ -61,7 +61,7 @@ function getBatchSize(totalRows: number, currentIndex: number): number { export class SerializationService implements ISerializationService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; private providers: { providerId: string, provider: azdata.SerializationProvider }[] = []; diff --git a/src/sql/platform/serverGroup/common/serverGroupController.ts b/src/sql/platform/serverGroup/common/serverGroupController.ts index c5cf523eac..c0f2749d49 100644 --- a/src/sql/platform/serverGroup/common/serverGroupController.ts +++ b/src/sql/platform/serverGroup/common/serverGroupController.ts @@ -13,7 +13,7 @@ export interface IServerGroupDialogCallbacks { } export const IServerGroupController = createDecorator('serverGroupController'); export interface IServerGroupController { - _serviceBrand: any; + _serviceBrand: undefined; showCreateGroupDialog(callbacks?: IServerGroupDialogCallbacks): Promise; showEditGroupDialog(group: ConnectionProfileGroup): Promise; } diff --git a/src/sql/platform/tasks/common/tasksService.ts b/src/sql/platform/tasks/common/tasksService.ts index ee11a303ec..4c353883af 100644 --- a/src/sql/platform/tasks/common/tasksService.ts +++ b/src/sql/platform/tasks/common/tasksService.ts @@ -18,7 +18,7 @@ export const SERVICE_ID = 'taskHistoryService'; export const ITaskService = createDecorator(SERVICE_ID); export interface ITaskService { - _serviceBrand: any; + _serviceBrand: undefined; onTaskComplete: Event; onAddNewTask: Event; handleNewTask(task: TaskNode): void; @@ -44,7 +44,7 @@ export interface TaskStatusChangeArgs { } export class TaskService implements ITaskService { - public _serviceBrand: any; + public _serviceBrand: undefined; private _taskQueue: TaskNode; private _onTaskComplete = new Emitter(); private _onAddNewTask = new Emitter(); @@ -160,7 +160,7 @@ export class TaskService implements ITaskService { let numOfInprogressTasks = this.getNumberOfInProgressTasks(); if (numOfInprogressTasks > 0) { this.dialogService.show(Severity.Warning, message, options).then(choice => { - switch (choice) { + switch (choice.choice) { case 0: let timeout: any; let isTimeout = false; diff --git a/src/sql/platform/telemetry/common/adsTelemetryService.ts b/src/sql/platform/telemetry/common/adsTelemetryService.ts index 7eaf5bb7c5..44bf76a5ce 100644 --- a/src/sql/platform/telemetry/common/adsTelemetryService.ts +++ b/src/sql/platform/telemetry/common/adsTelemetryService.ts @@ -56,7 +56,7 @@ class TelemetryEventImpl implements ITelemetryEvent { export class AdsTelemetryService implements IAdsTelemetryService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @ITelemetryService private telemetryService: ITelemetryService, diff --git a/src/sql/platform/telemetry/common/telemetry.ts b/src/sql/platform/telemetry/common/telemetry.ts index c8f10bee44..61fb1a116d 100644 --- a/src/sql/platform/telemetry/common/telemetry.ts +++ b/src/sql/platform/telemetry/common/telemetry.ts @@ -65,7 +65,7 @@ export interface ITelemetryInfo { export interface IAdsTelemetryService { // ITelemetryService functions - _serviceBrand: any; + _serviceBrand: undefined; setEnabled(value: boolean): void; diff --git a/src/sql/workbench/api/common/extHostNotebook.ts b/src/sql/workbench/api/common/extHostNotebook.ts index 9579f16e1b..c47b6632ca 100644 --- a/src/sql/workbench/api/common/extHostNotebook.ts +++ b/src/sql/workbench/api/common/extHostNotebook.ts @@ -285,7 +285,7 @@ export class ExtHostNotebook implements ExtHostNotebookShape { } } - private _withServerManager(handle: number, callback: (manager: azdata.nb.ServerManager) => R | PromiseLike): Promise { + private _withServerManager(handle: number, callback: (manager: azdata.nb.ServerManager) => PromiseLike): Promise { return this._withNotebookManager(handle, (notebookManager) => { let serverManager = notebookManager.serverManager; if (!serverManager) { @@ -295,7 +295,7 @@ export class ExtHostNotebook implements ExtHostNotebookShape { }); } - private _withContentManager(handle: number, callback: (manager: azdata.nb.ContentManager) => R | PromiseLike): Promise { + private _withContentManager(handle: number, callback: (manager: azdata.nb.ContentManager) => PromiseLike): Promise { return this._withNotebookManager(handle, (notebookManager) => { let contentManager = notebookManager.contentManager; if (!contentManager) { @@ -305,7 +305,7 @@ export class ExtHostNotebook implements ExtHostNotebookShape { }); } - private _withSessionManager(handle: number, callback: (manager: azdata.nb.SessionManager) => R | PromiseLike): Promise { + private _withSessionManager(handle: number, callback: (manager: azdata.nb.SessionManager) => PromiseLike): Promise { return this._withNotebookManager(handle, (notebookManager) => { let sessionManager = notebookManager.sessionManager; if (!sessionManager) { diff --git a/src/sql/workbench/browser/modelComponents/queryTextEditor.ts b/src/sql/workbench/browser/modelComponents/queryTextEditor.ts index 4e5b3fc943..aee011f587 100644 --- a/src/sql/workbench/browser/modelComponents/queryTextEditor.ts +++ b/src/sql/workbench/browser/modelComponents/queryTextEditor.ts @@ -22,7 +22,6 @@ import { StandaloneCodeEditor } from 'vs/editor/standalone/browser/standaloneCod import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { Configuration } from 'vs/editor/browser/config/configuration'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; @@ -151,7 +150,7 @@ export class QueryTextEditor extends BaseTextEditor { let shouldAddHorizontalScrollbarHeight = false; if (!this._editorWorkspaceConfig || configChanged) { this._editorWorkspaceConfig = this.workspaceConfigurationService.getValue('editor'); - this._lineHeight = editorWidget.getConfiguration().lineHeight; + this._lineHeight = editorWidget.getRawOptions().lineHeight; } let wordWrapEnabled: boolean = this._editorWorkspaceConfig && this._editorWorkspaceConfig['wordWrap'] && this._editorWorkspaceConfig['wordWrap'] === 'on' ? true : false; if (wordWrapEnabled) { diff --git a/src/sql/workbench/browser/parts/views/customView.ts b/src/sql/workbench/browser/parts/views/customView.ts index c4f9fdacf1..e1b10b9a0d 100644 --- a/src/sql/workbench/browser/parts/views/customView.ts +++ b/src/sql/workbench/browser/parts/views/customView.ts @@ -65,6 +65,7 @@ export class CustomTreeViewPanel extends ViewletPanel { const { treeView } = (Registry.as(Extensions.ViewsRegistry).getView(options.id)); this.treeView = treeView as ITreeView; this._register(this.treeView.onDidChangeActions(() => this.updateActions(), this)); + this._register(this.treeView.onDidChangeTitle((newTitle) => this.updateTitle(newTitle))); this._register(toDisposable(() => this.treeView.setVisibility(false))); this._register(this.onDidChangeBodyVisibility(() => this.updateTreeVisibility())); this.updateTreeVisibility(); @@ -200,11 +201,14 @@ export class CustomTreeView extends Disposable implements ITreeView { private readonly _onDidChangeActions: Emitter = this._register(new Emitter()); readonly onDidChangeActions: Event = this._onDidChangeActions.event; + private readonly _onDidChangeTitle: Emitter = this._register(new Emitter()); + readonly onDidChangeTitle: Event = this._onDidChangeTitle.event; + private nodeContext: NodeContextKey; constructor( private id: string, - private title: string, + private _title: string, private viewContainer: ViewContainer, @IExtensionService private readonly extensionService: IExtensionService, @IWorkbenchThemeService private readonly themeService: IWorkbenchThemeService, @@ -277,6 +281,15 @@ export class CustomTreeView extends Disposable implements ITreeView { this.updateMessage(); } + get title(): string { + return this._title; + } + + set title(name: string) { + this._title = name; + this._onDidChangeTitle.fire(this._title); + } + get canSelectMany(): boolean { return this._canSelectMany; } @@ -386,26 +399,26 @@ export class CustomTreeView extends Disposable implements ITreeView { const aligner = new Aligner(this.themeService); const renderer = this.instantiationService.createInstance(TreeRenderer, this.id, treeMenus, this.treeLabels, actionViewItemProvider, aligner); - this.tree = this._register(this.instantiationService.createInstance(WorkbenchAsyncDataTree, this.treeContainer, new CustomTreeDelegate(), [renderer], + this.tree = this._register(this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'SqlCustomView', this.treeContainer, new CustomTreeDelegate(), [renderer], dataSource, { - identityProvider: new CustomViewIdentityProvider(), - accessibilityProvider: { - getAriaLabel(element: ITreeItem): string { - return element.label ? element.label.label : ''; - } - }, - ariaLabel: this.title, - keyboardNavigationLabelProvider: { - getKeyboardNavigationLabel: (item: ITreeItem) => { - return item.label ? item.label.label : (item.resourceUri ? basename(URI.revive(item.resourceUri)) : undefined); - } - }, - expandOnlyOnTwistieClick: (e: ITreeItem) => !!e.command, - collapseByDefault: (e: ITreeItem): boolean => { - return e.collapsibleState !== TreeItemCollapsibleState.Expanded; - }, - multipleSelectionSupport: this.canSelectMany, - }) as WorkbenchAsyncDataTree); + identityProvider: new CustomViewIdentityProvider(), + accessibilityProvider: { + getAriaLabel(element: ITreeItem): string { + return element.label ? element.label.label : ''; + } + }, + ariaLabel: this.title, + keyboardNavigationLabelProvider: { + getKeyboardNavigationLabel: (item: ITreeItem) => { + return item.label ? item.label.label : (item.resourceUri ? basename(URI.revive(item.resourceUri)) : undefined); + } + }, + expandOnlyOnTwistieClick: (e: ITreeItem) => !!e.command, + collapseByDefault: (e: ITreeItem): boolean => { + return e.collapsibleState !== TreeItemCollapsibleState.Expanded; + }, + multipleSelectionSupport: this.canSelectMany, + }) as WorkbenchAsyncDataTree); aligner.tree = this.tree; const actionRunner = new MultipleSelectionActionRunner(() => this.tree!.getSelection()); renderer.actionRunner = actionRunner; diff --git a/src/sql/workbench/parts/charts/browser/interfaces.ts b/src/sql/workbench/parts/charts/browser/interfaces.ts index 02dad03f7d..8d98768776 100644 --- a/src/sql/workbench/parts/charts/browser/interfaces.ts +++ b/src/sql/workbench/parts/charts/browser/interfaces.ts @@ -47,6 +47,6 @@ export interface IInsight { } export interface IInsightCtor { - new(container: HTMLElement, options: IInsightOptions, ...services: { _serviceBrand: any; }[]): IInsight; + new(container: HTMLElement, options: IInsightOptions, ...services: { _serviceBrand: undefined; }[]): IInsight; readonly types: Array; } diff --git a/src/sql/workbench/parts/commandLine/test/electron-browser/commandLine.test.ts b/src/sql/workbench/parts/commandLine/test/electron-browser/commandLine.test.ts index 7f56a7cf6b..f288b1ef59 100644 --- a/src/sql/workbench/parts/commandLine/test/electron-browser/commandLine.test.ts +++ b/src/sql/workbench/parts/commandLine/test/electron-browser/commandLine.test.ts @@ -43,24 +43,24 @@ class TestParsedArgs implements ParsedArgs { debugPluginHost?: string; debugSearch?: string; diff?: boolean; - 'disable-crash-reporter'?: string; - 'disable-extension'?: string | string[]; + 'disable-crash-reporter'?: boolean; + 'disable-extension'?: string[]; // undefined or array of 1 or more 'disable-extensions'?: boolean; 'disable-restore-windows'?: boolean; 'disable-telemetry'?: boolean; - 'disable-updates'?: string; + 'disable-updates'?: boolean; 'driver'?: string; - 'enable-proposed-api'?: string | string[]; + 'enable-proposed-api'?: string[]; 'export-default-configuration'?: string; 'extensions-dir'?: string; - extensionDevelopmentPath?: string; + extensionDevelopmentPath?: string[]; extensionTestsPath?: string; 'file-chmod'?: boolean; 'file-write'?: boolean; - 'folder-uri'?: string | string[]; + 'folder-uri'?: string[]; goto?: boolean; help?: boolean; - 'install-extension'?: string | string[]; + 'install-extension'?: string[]; 'install-source'?: string; integrated?: boolean; 'list-extensions'?: boolean; @@ -72,7 +72,7 @@ class TestParsedArgs implements ParsedArgs { 'open-url'?: boolean; performance?: boolean; 'prof-append-timers'?: string; - 'prof-startup'?: string; + 'prof-startup'?: boolean; 'prof-startup-prefix'?: string; 'reuse-window'?: boolean; server?: string; @@ -82,7 +82,7 @@ class TestParsedArgs implements ParsedArgs { 'skip-release-notes'?: boolean; status?: boolean; 'sticky-quickopen'?: boolean; - 'uninstall-extension'?: string | string[]; + 'uninstall-extension'?: string[]; 'unity-launch'?: boolean; // Always open a new window, except if opening the first window or opening a file or folder as part of the launch. 'upload-logs'?: string; user?: string; diff --git a/src/sql/workbench/parts/notebook/test/electron-browser/cell.test.ts b/src/sql/workbench/parts/notebook/test/electron-browser/cell.test.ts index 0d40387493..fece3e66bc 100644 --- a/src/sql/workbench/parts/notebook/test/electron-browser/cell.test.ts +++ b/src/sql/workbench/parts/notebook/test/electron-browser/cell.test.ts @@ -269,13 +269,13 @@ suite('Cell Model', function (): void { metadata: { language: 'python' }, execution_count: 1 }, { - notebook: new NotebookModelStub({ - name: '', - version: '', - mimetype: 'x-scala' - }), - isTrusted: false - }); + notebook: new NotebookModelStub({ + name: '', + version: '', + mimetype: 'x-scala' + }), + isTrusted: false + }); }); test('should send and handle incoming messages', async () => { diff --git a/src/sql/workbench/parts/objectExplorer/browser/objectExplorerViewTreeShim.ts b/src/sql/workbench/parts/objectExplorer/browser/objectExplorerViewTreeShim.ts index b13cf14991..8b52f51e7a 100644 --- a/src/sql/workbench/parts/objectExplorer/browser/objectExplorerViewTreeShim.ts +++ b/src/sql/workbench/parts/objectExplorer/browser/objectExplorerViewTreeShim.ts @@ -23,7 +23,7 @@ export const SERVICE_ID = 'oeShimService'; export const IOEShimService = createDecorator(SERVICE_ID); export interface IOEShimService { - _serviceBrand: any; + _serviceBrand: undefined; getChildren(node: ITreeItem, viewId: string): Promise; disconnectNode(viewId: string, node: ITreeItem): Promise; providerExists(providerId: string): boolean; @@ -32,7 +32,7 @@ export interface IOEShimService { } export class OEShimService extends Disposable implements IOEShimService { - _serviceBrand: any; + _serviceBrand: undefined; private sessionMap = new Map(); private nodeHandleMap = new Map(); diff --git a/src/sql/workbench/parts/objectExplorer/test/browser/connectionTreeActions.test.ts b/src/sql/workbench/parts/objectExplorer/test/browser/connectionTreeActions.test.ts index dcee2945ed..1e854676ca 100644 --- a/src/sql/workbench/parts/objectExplorer/test/browser/connectionTreeActions.test.ts +++ b/src/sql/workbench/parts/objectExplorer/test/browser/connectionTreeActions.test.ts @@ -107,7 +107,7 @@ suite('SQL Connection Tree Action tests', () => { }); const viewsService = new class implements IViewsService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; openView(id: string, focus?: boolean): Promise { return Promise.resolve({ id: '', diff --git a/src/sql/workbench/parts/profiler/browser/profilerEditor.ts b/src/sql/workbench/parts/profiler/browser/profilerEditor.ts index 59bc7640d8..d46199ff48 100644 --- a/src/sql/workbench/parts/profiler/browser/profilerEditor.ts +++ b/src/sql/workbench/parts/profiler/browser/profilerEditor.ts @@ -382,9 +382,9 @@ export class ProfilerEditor extends BaseEditor { } ] }, { - forceFitColumns: true, - dataItemColumnValueExtractor: slickGridDataItemColumnValueExtractor - }); + forceFitColumns: true, + dataItemColumnValueExtractor: slickGridDataItemColumnValueExtractor + }); this._detailTableData.onRowCountChange(() => { this._detailTable.updateRowCount(); diff --git a/src/sql/workbench/parts/profiler/browser/profilerInput.ts b/src/sql/workbench/parts/profiler/browser/profilerInput.ts index 4c6ab657d3..41676d7122 100644 --- a/src/sql/workbench/parts/profiler/browser/profilerInput.ts +++ b/src/sql/workbench/parts/profiler/browser/profilerInput.ts @@ -17,7 +17,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { INotificationService } from 'vs/platform/notification/common/notification'; import { Event, Emitter } from 'vs/base/common/event'; import { generateUuid } from 'vs/base/common/uuid'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IDialogService, IShowResult } from 'vs/platform/dialogs/common/dialogs'; import * as types from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import Severity from 'vs/base/common/severity'; @@ -291,11 +291,11 @@ export class ProfilerInput extends EditorInput implements IProfilerSession { nls.localize('profilerClosingActions.yes', "Yes"), nls.localize('profilerClosingActions.no', "No"), nls.localize('profilerClosingActions.cancel', "Cancel") - ]).then((selection: number) => { - if (selection === 0) { + ]).then((selection: IShowResult) => { + if (selection.choice === 0) { this._profilerService.stopSession(this.id); return ConfirmResult.DONT_SAVE; - } else if (selection === 1) { + } else if (selection.choice === 1) { return ConfirmResult.DONT_SAVE; } else { return ConfirmResult.CANCEL; diff --git a/src/sql/workbench/parts/profiler/browser/profilerTableEditor.ts b/src/sql/workbench/parts/profiler/browser/profilerTableEditor.ts index 5ea46eceba..9c4d2dcbaa 100644 --- a/src/sql/workbench/parts/profiler/browser/profilerTableEditor.ts +++ b/src/sql/workbench/parts/profiler/browser/profilerTableEditor.ts @@ -92,8 +92,8 @@ export class ProfilerTableEditor extends BaseEditor implements IProfilerControll } } }, { - dataItemColumnValueExtractor: slickGridDataItemColumnValueExtractor - }); + dataItemColumnValueExtractor: slickGridDataItemColumnValueExtractor + }); this._profilerTable.setSelectionModel(new RowSelectionModel()); const copyKeybind = new CopyKeybind(); copyKeybind.onCopy((e) => { diff --git a/src/sql/workbench/parts/query/browser/queryResultsEditor.ts b/src/sql/workbench/parts/query/browser/queryResultsEditor.ts index 184eea1ea6..0ee8825fcd 100644 --- a/src/sql/workbench/parts/query/browser/queryResultsEditor.ts +++ b/src/sql/workbench/parts/query/browser/queryResultsEditor.ts @@ -28,9 +28,9 @@ export class BareResultsGridInfo extends BareFontInfo { public static createFromRawSettings(opts: { fontFamily?: string; fontWeight?: string; - fontSize?: number | string; - lineHeight?: number | string; - letterSpacing?: number | string; + fontSize?: number; + lineHeight?: number; + letterSpacing?: number; cellPadding?: number | number[]; }, zoomLevel: number): BareResultsGridInfo { let cellPadding = !types.isUndefinedOrNull(opts.cellPadding) ? opts.cellPadding : RESULTS_GRID_DEFAULTS.cellPadding; diff --git a/src/sql/workbench/parts/queryHistory/browser/queryHistoryView.ts b/src/sql/workbench/parts/queryHistory/browser/queryHistoryView.ts index a0338d5620..4fda4e27bc 100644 --- a/src/sql/workbench/parts/queryHistory/browser/queryHistoryView.ts +++ b/src/sql/workbench/parts/queryHistory/browser/queryHistoryView.ts @@ -75,10 +75,10 @@ export class QueryHistoryView extends Disposable { return new Tree(treeContainer, { dataSource, renderer, controller, dnd, filter, sorter, accessibilityProvider }, { - indentPixels: 10, - twistiePixels: 20, - ariaLabel: localize({ key: 'queryHistory.regTreeAriaLabel', comment: ['QueryHistory'] }, "Query History") - }); + indentPixels: 10, + twistiePixels: 20, + ariaLabel: localize({ key: 'queryHistory.regTreeAriaLabel', comment: ['QueryHistory'] }, "Query History") + }); } public refreshTree(): void { diff --git a/src/sql/workbench/parts/tasks/browser/tasksView.ts b/src/sql/workbench/parts/tasks/browser/tasksView.ts index ec1f29de86..46d839b37a 100644 --- a/src/sql/workbench/parts/tasks/browser/tasksView.ts +++ b/src/sql/workbench/parts/tasks/browser/tasksView.ts @@ -90,10 +90,10 @@ export class TaskHistoryView extends Disposable { return new Tree(treeContainer, { dataSource, renderer, controller, dnd, filter, sorter, accessibilityProvider }, { - indentPixels: 10, - twistiePixels: 20, - ariaLabel: localize({ key: 'taskHistory.regTreeAriaLabel', comment: ['TaskHistory'] }, "Task history") - }); + indentPixels: 10, + twistiePixels: 20, + ariaLabel: localize({ key: 'taskHistory.regTreeAriaLabel', comment: ['TaskHistory'] }, "Task history") + }); } private updateTask(task: TaskNode): void { diff --git a/src/sql/workbench/services/accountManagement/browser/accountManagementService.ts b/src/sql/workbench/services/accountManagement/browser/accountManagementService.ts index dcab85f8cf..f95b0abd6e 100644 --- a/src/sql/workbench/services/accountManagement/browser/accountManagementService.ts +++ b/src/sql/workbench/services/accountManagement/browser/accountManagementService.ts @@ -27,7 +27,7 @@ export class AccountManagementService implements IAccountManagementService { // MEMBER VARIABLES //////////////////////////////////////////////////// public _providers: { [id: string]: AccountProviderWithMetadata } = {}; - public _serviceBrand: any; + public _serviceBrand: undefined; private _accountStore: AccountStore; private _accountDialogController: AccountDialogController; private _autoOAuthDialogController: AutoOAuthDialogController; diff --git a/src/sql/workbench/services/admin/common/adminService.ts b/src/sql/workbench/services/admin/common/adminService.ts index 24b525b859..9873f8be34 100644 --- a/src/sql/workbench/services/admin/common/adminService.ts +++ b/src/sql/workbench/services/admin/common/adminService.ts @@ -15,7 +15,7 @@ import * as azdata from 'azdata'; export const IAdminService = createDecorator(SERVICE_ID); export interface IAdminService { - _serviceBrand: any; + _serviceBrand: undefined; registerProvider(providerId: string, provider: azdata.AdminServicesProvider): void; @@ -25,7 +25,7 @@ export interface IAdminService { } export class AdminService implements IAdminService { - _serviceBrand: any; + _serviceBrand: undefined; private _providers: { [handle: string]: azdata.AdminServicesProvider; } = Object.create(null); diff --git a/src/sql/workbench/services/backup/browser/backupUiService.ts b/src/sql/workbench/services/backup/browser/backupUiService.ts index 4bab854cc0..2f752a7759 100644 --- a/src/sql/workbench/services/backup/browser/backupUiService.ts +++ b/src/sql/workbench/services/backup/browser/backupUiService.ts @@ -19,7 +19,7 @@ import { IBackupService, TaskExecutionMode } from 'sql/platform/backup/common/ba import { IBackupUiService } from 'sql/workbench/services/backup/common/backupUiService'; export class BackupUiService implements IBackupUiService { - public _serviceBrand: any; + public _serviceBrand: undefined; private _backupDialogs: { [providerName: string]: BackupDialog | OptionsDialog } = {}; private _currentProvider: string; private _optionValues: { [optionName: string]: any } = {}; diff --git a/src/sql/workbench/services/backup/common/backupUiService.ts b/src/sql/workbench/services/backup/common/backupUiService.ts index ac60150f26..a41a20e62d 100644 --- a/src/sql/workbench/services/backup/common/backupUiService.ts +++ b/src/sql/workbench/services/backup/common/backupUiService.ts @@ -11,7 +11,7 @@ export const UI_SERVICE_ID = 'backupUiService'; export const IBackupUiService = createDecorator(UI_SERVICE_ID); export interface IBackupUiService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Show backup wizard diff --git a/src/sql/workbench/services/connection/browser/connectionDialogService.ts b/src/sql/workbench/services/connection/browser/connectionDialogService.ts index 2e88c0d6e6..be38cbf9d9 100644 --- a/src/sql/workbench/services/connection/browser/connectionDialogService.ts +++ b/src/sql/workbench/services/connection/browser/connectionDialogService.ts @@ -58,7 +58,7 @@ export interface IConnectionComponentController { export class ConnectionDialogService implements IConnectionDialogService { - _serviceBrand: any; + _serviceBrand: undefined; private _connectionDialog: ConnectionDialogWidget; private _connectionControllerMap: { [providerName: string]: IConnectionComponentController } = {}; @@ -277,14 +277,14 @@ export class ConnectionDialogService implements IConnectionDialogService { this._connectionControllerMap[providerName] = this._instantiationService.createInstance(CmsConnectionController, this._capabilitiesService.getCapabilities(providerName).connection, { - onSetConnectButton: (enable: boolean) => this.handleSetConnectButtonEnable(enable) - }, providerName); + onSetConnectButton: (enable: boolean) => this.handleSetConnectButtonEnable(enable) + }, providerName); } else { this._connectionControllerMap[providerName] = this._instantiationService.createInstance(ConnectionController, this._capabilitiesService.getCapabilities(providerName).connection, { - onSetConnectButton: (enable: boolean) => this.handleSetConnectButtonEnable(enable) - }, providerName); + onSetConnectButton: (enable: boolean) => this.handleSetConnectButtonEnable(enable) + }, providerName); } } return this._connectionControllerMap[providerName]; diff --git a/src/sql/workbench/services/connection/common/connectionDialogService.ts b/src/sql/workbench/services/connection/common/connectionDialogService.ts index 6521074cc8..04253123cf 100644 --- a/src/sql/workbench/services/connection/common/connectionDialogService.ts +++ b/src/sql/workbench/services/connection/common/connectionDialogService.ts @@ -9,7 +9,7 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; export const IConnectionDialogService = createDecorator('connectionDialogService'); export interface IConnectionDialogService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Opens the connection dialog and returns the promise for successfully opening the dialog */ diff --git a/src/sql/workbench/services/connection/test/common/testConnectionDialogService.ts b/src/sql/workbench/services/connection/test/common/testConnectionDialogService.ts index cffc48a7b1..b81ee95d46 100644 --- a/src/sql/workbench/services/connection/test/common/testConnectionDialogService.ts +++ b/src/sql/workbench/services/connection/test/common/testConnectionDialogService.ts @@ -8,7 +8,7 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; import { IConnectionDialogService } from 'sql/workbench/services/connection/common/connectionDialogService'; export class TestConnectionDialogService implements IConnectionDialogService { - _serviceBrand: any; + _serviceBrand: undefined; public showDialog(connectionManagementService: IConnectionManagementService, params: INewConnectionParams, model: IConnectionProfile, connectionResult?: IConnectionResult, connectionOptions?: IConnectionCompletionOptions): Promise { diff --git a/src/sql/workbench/services/dashboard/browser/newDashboardTabDialog.ts b/src/sql/workbench/services/dashboard/browser/newDashboardTabDialog.ts index 797eb47f86..94b451a6fd 100644 --- a/src/sql/workbench/services/dashboard/browser/newDashboardTabDialog.ts +++ b/src/sql/workbench/services/dashboard/browser/newDashboardTabDialog.ts @@ -8,6 +8,6 @@ import { IDashboardTab } from 'sql/platform/dashboard/browser/dashboardRegistry' export const INewDashboardTabDialogService = createDecorator('addNewDashboardTabService'); export interface INewDashboardTabDialogService { - _serviceBrand: any; + _serviceBrand: undefined; showDialog(dashboardTabs: Array, openedTabs: Array, uri: string): void; } diff --git a/src/sql/workbench/services/dashboard/browser/newDashboardTabDialogImpl.ts b/src/sql/workbench/services/dashboard/browser/newDashboardTabDialogImpl.ts index 7f52b08e94..c2acfa6524 100644 --- a/src/sql/workbench/services/dashboard/browser/newDashboardTabDialogImpl.ts +++ b/src/sql/workbench/services/dashboard/browser/newDashboardTabDialogImpl.ts @@ -169,7 +169,7 @@ export class NewDashboardTabDialog extends Modal { let extensionTabViewContainer = DOM.$('.extensionTab-view'); let delegate = new ExtensionListDelegate(); let extensionTabRenderer = new ExtensionListRenderer(); - this._extensionList = new List(extensionTabViewContainer, delegate, [extensionTabRenderer]); + this._extensionList = new List('NewDashboardTabExtentionList', extensionTabViewContainer, delegate, [extensionTabRenderer]); this._extensionList.onMouseDblClick(e => this.onAccept()); this._extensionList.onKeyDown(e => { diff --git a/src/sql/workbench/services/dashboard/browser/newDashboardTabDialogService.ts b/src/sql/workbench/services/dashboard/browser/newDashboardTabDialogService.ts index fdcba5125d..5762ddb446 100644 --- a/src/sql/workbench/services/dashboard/browser/newDashboardTabDialogService.ts +++ b/src/sql/workbench/services/dashboard/browser/newDashboardTabDialogService.ts @@ -12,7 +12,7 @@ import { IDashboardUITab } from 'sql/workbench/services/dashboard/browser/newDas import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; export class NewDashboardTabDialogService implements INewDashboardTabDialogService { - _serviceBrand: any; + _serviceBrand: undefined; // MEMBER VARIABLES //////////////////////////////////////////////////// private _addNewTabDialog: NewDashboardTabDialog; diff --git a/src/sql/workbench/services/errorMessage/browser/errorMessageService.ts b/src/sql/workbench/services/errorMessage/browser/errorMessageService.ts index 5fee1f0a9f..a2cb47841e 100644 --- a/src/sql/workbench/services/errorMessage/browser/errorMessageService.ts +++ b/src/sql/workbench/services/errorMessage/browser/errorMessageService.ts @@ -13,7 +13,7 @@ import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMess export class ErrorMessageService implements IErrorMessageService { - _serviceBrand: any; + _serviceBrand: undefined; private _errorDialog: ErrorMessageDialog; @@ -53,4 +53,4 @@ export class ErrorMessageService implements IErrorMessageService { } return defaultTitle; } -} \ No newline at end of file +} diff --git a/src/sql/workbench/services/fileBrowser/browser/fileBrowserDialogController.ts b/src/sql/workbench/services/fileBrowser/browser/fileBrowserDialogController.ts index 249461b798..b8a6ff1acb 100644 --- a/src/sql/workbench/services/fileBrowser/browser/fileBrowserDialogController.ts +++ b/src/sql/workbench/services/fileBrowser/browser/fileBrowserDialogController.ts @@ -12,7 +12,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti * File browser dialog service */ export class FileBrowserDialogController implements IFileBrowserDialogController { - _serviceBrand: any; + _serviceBrand: undefined; private _fileBrowserDialog: FileBrowserDialog; constructor( diff --git a/src/sql/workbench/services/fileBrowser/browser/fileBrowserTreeView.ts b/src/sql/workbench/services/fileBrowser/browser/fileBrowserTreeView.ts index 04ca9a51cb..413e7be7d8 100644 --- a/src/sql/workbench/services/fileBrowser/browser/fileBrowserTreeView.ts +++ b/src/sql/workbench/services/fileBrowser/browser/fileBrowserTreeView.ts @@ -76,10 +76,10 @@ export class FileBrowserTreeView extends Disposable implements IDisposable { return new Tree(treeContainer, { dataSource, renderer, controller, dnd, filter, sorter, accessibilityProvider }, { - indentPixels: 10, - twistiePixels: 12, - ariaLabel: nls.localize({ key: 'fileBrowser.regTreeAriaLabel', comment: ['FileBrowserTree'] }, "File browser tree") - }); + indentPixels: 10, + twistiePixels: 12, + ariaLabel: nls.localize({ key: 'fileBrowser.regTreeAriaLabel', comment: ['FileBrowserTree'] }, "File browser tree") + }); } /** diff --git a/src/sql/workbench/services/fileBrowser/common/fileBrowserDialogController.ts b/src/sql/workbench/services/fileBrowser/common/fileBrowserDialogController.ts index 3547f91a77..16df3568ae 100644 --- a/src/sql/workbench/services/fileBrowser/common/fileBrowserDialogController.ts +++ b/src/sql/workbench/services/fileBrowser/common/fileBrowserDialogController.ts @@ -7,7 +7,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export const IFileBrowserDialogController = createDecorator('fileBrowserDialogService'); export interface IFileBrowserDialogController { - _serviceBrand: any; + _serviceBrand: undefined; /** * Show file browser dialog */ diff --git a/src/sql/workbench/services/insights/browser/insightsDialogService.ts b/src/sql/workbench/services/insights/browser/insightsDialogService.ts index defa4950d0..fe8bc7eff5 100644 --- a/src/sql/workbench/services/insights/browser/insightsDialogService.ts +++ b/src/sql/workbench/services/insights/browser/insightsDialogService.ts @@ -30,7 +30,7 @@ export interface ListResource { export const IInsightsDialogService = createDecorator('insightsDialogService'); export interface IInsightsDialogService { - _serviceBrand: any; + _serviceBrand: undefined; show(input: IInsightsConfig, connectionProfile: IConnectionProfile): void; close(); } diff --git a/src/sql/workbench/services/insights/browser/insightsDialogServiceImpl.ts b/src/sql/workbench/services/insights/browser/insightsDialogServiceImpl.ts index 822a0fdac9..c5f2c72390 100644 --- a/src/sql/workbench/services/insights/browser/insightsDialogServiceImpl.ts +++ b/src/sql/workbench/services/insights/browser/insightsDialogServiceImpl.ts @@ -12,7 +12,7 @@ import { IInsightsConfig } from 'sql/platform/dashboard/browser/insightRegistry' import { InsightsDialogController } from 'sql/workbench/services/insights/browser/insightsDialogController'; export class InsightsDialogService implements IInsightsDialogService { - _serviceBrand: any; + _serviceBrand: undefined; private _insightsDialogController: InsightsDialogController; private _insightsDialogView: InsightsDialogView; private _insightsDialogModel: IInsightsDialogModel; diff --git a/src/sql/workbench/services/insights/test/electron-browser/insightsUtils.test.ts b/src/sql/workbench/services/insights/test/electron-browser/insightsUtils.test.ts index ddaee5fd65..a750245a94 100644 --- a/src/sql/workbench/services/insights/test/electron-browser/insightsUtils.test.ts +++ b/src/sql/workbench/services/insights/test/electron-browser/insightsUtils.test.ts @@ -51,7 +51,7 @@ class TestEnvironmentService implements IWorkbenchEnvironmentService { } as IWindowConfiguration; } - _serviceBrand: any; + _serviceBrand: undefined; args: ParsedArgs; execPath: string; cliPath: string; diff --git a/src/sql/workbench/services/notebook/browser/notebookService.ts b/src/sql/workbench/services/notebook/browser/notebookService.ts index b95902e57e..c85022fdc5 100644 --- a/src/sql/workbench/services/notebook/browser/notebookService.ts +++ b/src/sql/workbench/services/notebook/browser/notebookService.ts @@ -33,7 +33,7 @@ export interface ILanguageMagic { } export interface INotebookService { - _serviceBrand: any; + _serviceBrand: undefined; readonly onNotebookEditorAdd: Event; readonly onNotebookEditorRemove: Event; diff --git a/src/sql/workbench/services/notebook/browser/notebookServiceImpl.ts b/src/sql/workbench/services/notebook/browser/notebookServiceImpl.ts index b7473a22b3..585cc4f11f 100644 --- a/src/sql/workbench/services/notebook/browser/notebookServiceImpl.ts +++ b/src/sql/workbench/services/notebook/browser/notebookServiceImpl.ts @@ -92,7 +92,7 @@ class ProviderDescriptor { } export class NotebookService extends Disposable implements INotebookService { - _serviceBrand: any; + _serviceBrand: undefined; private _providersMemento: Memento; private _trustedNotebooksMemento: Memento; diff --git a/src/sql/workbench/services/objectExplorer/browser/objectExplorerService.ts b/src/sql/workbench/services/objectExplorer/browser/objectExplorerService.ts index 383c38f5fe..f65e50d399 100644 --- a/src/sql/workbench/services/objectExplorer/browser/objectExplorerService.ts +++ b/src/sql/workbench/services/objectExplorer/browser/objectExplorerService.ts @@ -30,7 +30,7 @@ export interface NodeExpandInfoWithProviderId extends azdata.ObjectExplorerExpan } export interface IObjectExplorerService { - _serviceBrand: any; + _serviceBrand: undefined; createNewSession(providerId: string, connection: ConnectionProfile): Thenable; @@ -127,7 +127,7 @@ const errSessionCreateFailed = nls.localize('OeSessionFailedError', "Failed to c export class ObjectExplorerService implements IObjectExplorerService { - public _serviceBrand: any; + public _serviceBrand: undefined; private _providers: { [handle: string]: azdata.ObjectExplorerProvider; } = Object.create(null); @@ -595,11 +595,11 @@ export class ObjectExplorerService implements IObjectExplorerService { let node = new TreeNode(nodeInfo.nodeType, nodeInfo.label, isLeaf, nodeInfo.nodePath, nodeInfo.nodeSubType, nodeInfo.nodeStatus, parent, nodeInfo.metadata, nodeInfo.iconType, { - getChildren: treeNode => this.getChildren(treeNode), - isExpanded: treeNode => this.isExpanded(treeNode), - setNodeExpandedState: async (treeNode, expandedState) => await this.setNodeExpandedState(treeNode, expandedState), - setNodeSelected: (treeNode, selected, clearOtherSelections: boolean = undefined) => this.setNodeSelected(treeNode, selected, clearOtherSelections) - }); + getChildren: treeNode => this.getChildren(treeNode), + isExpanded: treeNode => this.isExpanded(treeNode), + setNodeExpandedState: async (treeNode, expandedState) => await this.setNodeExpandedState(treeNode, expandedState), + setNodeSelected: (treeNode, selected, clearOtherSelections: boolean = undefined) => this.setNodeSelected(treeNode, selected, clearOtherSelections) + }); node.childProvider = nodeInfo.childProvider; node.payload = nodeInfo.payload; return node; diff --git a/src/sql/workbench/services/profiler/browser/interfaces.ts b/src/sql/workbench/services/profiler/browser/interfaces.ts index b42d7dbb1a..71bfa69bd2 100644 --- a/src/sql/workbench/services/profiler/browser/interfaces.ts +++ b/src/sql/workbench/services/profiler/browser/interfaces.ts @@ -46,7 +46,7 @@ export interface IProfilerSession { * A Profiler Service that handles session communication between the backends and frontends */ export interface IProfilerService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Registers a backend provider for profiler session. ex: mssql */ @@ -194,4 +194,4 @@ export enum ProfilerFilterClauseOperator { NotContains, StartsWith, NotStartsWith -} \ No newline at end of file +} diff --git a/src/sql/workbench/services/profiler/browser/profilerService.ts b/src/sql/workbench/services/profiler/browser/profilerService.ts index 03060566a5..6ac69c2675 100644 --- a/src/sql/workbench/services/profiler/browser/profilerService.ts +++ b/src/sql/workbench/services/profiler/browser/profilerService.ts @@ -46,7 +46,7 @@ class TwoWayMap { export class ProfilerService implements IProfilerService { private static readonly PROFILER_SERVICE_UI_STATE_STORAGE_KEY = 'profileservice.uiState'; - public _serviceBrand: any; + public _serviceBrand: undefined; private _providers = new Map(); private _idMap = new TwoWayMap(); private _sessionMap = new Map(); diff --git a/src/sql/workbench/services/queryEditor/browser/editorDescriptorService.ts b/src/sql/workbench/services/queryEditor/browser/editorDescriptorService.ts index e6da4f758b..1c936a4974 100644 --- a/src/sql/workbench/services/queryEditor/browser/editorDescriptorService.ts +++ b/src/sql/workbench/services/queryEditor/browser/editorDescriptorService.ts @@ -10,13 +10,13 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export interface IEditorDescriptorService { - _serviceBrand: any; + _serviceBrand: undefined; getEditor(input: EditorInput): IEditorDescriptor; } export class EditorDescriptorService implements IEditorDescriptorService { - public _serviceBrand: any; + public _serviceBrand: undefined; constructor() { } @@ -28,4 +28,4 @@ export class EditorDescriptorService implements IEditorDescriptorService { export const SERVICE_ID = 'editorDescriptorService'; -export const IEditorDescriptorService = createDecorator(SERVICE_ID); \ No newline at end of file +export const IEditorDescriptorService = createDecorator(SERVICE_ID); diff --git a/src/sql/workbench/services/queryEditor/browser/queryEditorService.ts b/src/sql/workbench/services/queryEditor/browser/queryEditorService.ts index 0fcf675f30..a607157180 100644 --- a/src/sql/workbench/services/queryEditor/browser/queryEditorService.ts +++ b/src/sql/workbench/services/queryEditor/browser/queryEditorService.ts @@ -36,7 +36,7 @@ import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileE */ export class QueryEditorService implements IQueryEditorService { - public _serviceBrand: any; + public _serviceBrand: undefined; private static CHANGE_UNSUPPORTED_ERROR_MESSAGE = nls.localize( 'queryEditorServiceChangeUnsupportedError', diff --git a/src/sql/workbench/services/queryEditor/common/queryEditorService.ts b/src/sql/workbench/services/queryEditor/common/queryEditorService.ts index 0c23e52f66..0a934b846d 100644 --- a/src/sql/workbench/services/queryEditor/common/queryEditorService.ts +++ b/src/sql/workbench/services/queryEditor/common/queryEditorService.ts @@ -23,7 +23,7 @@ export const IQueryEditorService = createDecorator('QueryEd export interface IQueryEditorService { - _serviceBrand: any; + _serviceBrand: undefined; // Creates new untitled document for SQL queries and opens it in a new editor tab newSqlEditor(sqlContent?: string, connectionProviderName?: string, isDirty?: boolean, objectName?: string): Promise; diff --git a/src/sql/workbench/services/resourceProvider/browser/resourceProviderService.ts b/src/sql/workbench/services/resourceProvider/browser/resourceProviderService.ts index ba29904dc3..8dc791b06a 100644 --- a/src/sql/workbench/services/resourceProvider/browser/resourceProviderService.ts +++ b/src/sql/workbench/services/resourceProvider/browser/resourceProviderService.ts @@ -18,7 +18,7 @@ import { ILogService } from 'vs/platform/log/common/log'; export class ResourceProviderService implements IResourceProviderService { - public _serviceBrand: any; + public _serviceBrand: undefined; private _providers: { [handle: string]: azdata.ResourceProvider; } = Object.create(null); private _firewallRuleDialogController: FirewallRuleDialogController; diff --git a/src/sql/workbench/services/resourceProvider/common/resourceProviderService.ts b/src/sql/workbench/services/resourceProvider/common/resourceProviderService.ts index 818df2afc9..40b9445913 100644 --- a/src/sql/workbench/services/resourceProvider/common/resourceProviderService.ts +++ b/src/sql/workbench/services/resourceProvider/common/resourceProviderService.ts @@ -19,7 +19,7 @@ export interface IHandleFirewallRuleResult { } export interface IResourceProviderService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Register a resource provider diff --git a/src/sql/workbench/services/resourceProvider/test/common/testResourceProviderService.ts b/src/sql/workbench/services/resourceProvider/test/common/testResourceProviderService.ts index fad46b1073..161d887ecf 100644 --- a/src/sql/workbench/services/resourceProvider/test/common/testResourceProviderService.ts +++ b/src/sql/workbench/services/resourceProvider/test/common/testResourceProviderService.ts @@ -8,7 +8,7 @@ import { IHandleFirewallRuleResult, IResourceProviderService } from 'sql/workben import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; export class TestResourceProvider implements IResourceProviderService { - _serviceBrand: any; + _serviceBrand: undefined; registerProvider(providerId: string, provider: azdata.ResourceProvider): void { diff --git a/src/sql/workbench/services/serverGroup/browser/serverGroupController.ts b/src/sql/workbench/services/serverGroup/browser/serverGroupController.ts index 5a2c2d65e0..bd19b40436 100644 --- a/src/sql/workbench/services/serverGroup/browser/serverGroupController.ts +++ b/src/sql/workbench/services/serverGroup/browser/serverGroupController.ts @@ -16,7 +16,7 @@ import { ServerGroupViewModel } from 'sql/workbench/parts/objectExplorer/common/ import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; export class ServerGroupController implements IServerGroupController { - _serviceBrand: any; + _serviceBrand: undefined; private _serverGroupDialog: ServerGroupDialog; private _callbacks: IServerGroupDialogCallbacks; diff --git a/src/sql/workbench/update/electron-browser/releaseNotes.ts b/src/sql/workbench/update/electron-browser/releaseNotes.ts index a5f7c84bf8..c3cc330d88 100644 --- a/src/sql/workbench/update/electron-browser/releaseNotes.ts +++ b/src/sql/workbench/update/electron-browser/releaseNotes.ts @@ -11,7 +11,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { URI } from 'vs/base/common/uri'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; -import { AbstractShowReleaseNotesAction } from 'vs/workbench/contrib/update/electron-browser/update'; +import { AbstractShowReleaseNotesAction } from 'vs/workbench/contrib/update/browser/update'; export class OpenGettingStartedInBrowserAction extends Action { diff --git a/src/tsconfig.base.json b/src/tsconfig.base.json index b3ef78e4a9..c901bb3782 100644 --- a/src/tsconfig.base.json +++ b/src/tsconfig.base.json @@ -3,7 +3,6 @@ "module": "amd", "moduleResolution": "node", "noImplicitAny": false, - "target": "es5", "experimentalDecorators": true, "noImplicitReturns": true, "noUnusedLocals": false, diff --git a/src/tsconfig.json b/src/tsconfig.json index eb94959e88..ca5caf9630 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -5,12 +5,11 @@ "preserveConstEnums": true, "sourceMap": false, "outDir": "../out", - "target": "es6", + "target": "es2017", "lib": [ "dom", "es5", - "es2015.iterable", - "webworker" + "es2015.iterable" ], "types": [ "keytar", @@ -27,6 +26,9 @@ "./sqltest" ], "exclude": [ - "./typings/require-monaco.d.ts" + "./typings/require-monaco.d.ts", + "./typings/xterm.d.ts", + "./typings/xterm-addon-search.d.ts", + "./typings/xterm-addon-web-links.d.ts" ] } diff --git a/src/typings/electron.d.ts b/src/typings/electron.d.ts index cc80376a76..6f44785756 100644 --- a/src/typings/electron.d.ts +++ b/src/typings/electron.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Electron 4.2.9 +// Type definitions for Electron 4.2.10 // Project: http://electronjs.org/ // Definitions by: The Electron Team // Definitions: https://github.com/electron/electron-typescript-definitions @@ -9861,4 +9861,4 @@ declare namespace NodeJS { electron: string; chrome: string; } -} \ No newline at end of file +} diff --git a/src/typings/globals/core-js/index.d.ts b/src/typings/globals/core-js/index.d.ts index 8ce32ed9d9..e366377d0d 100644 --- a/src/typings/globals/core-js/index.d.ts +++ b/src/typings/globals/core-js/index.d.ts @@ -619,11 +619,6 @@ declare var WeakSet: WeakSetConstructor; // Modules: es6.string.iterator, es6.array.iterator, es6.map, es6.set, web.dom.iterable // ############################################################################################# -interface IteratorResult { - done: boolean; - value: T; -} - interface Iterator { next(value?: any): IteratorResult; return?(value?: any): IteratorResult; diff --git a/src/typings/jQuery.d.ts b/src/typings/jQuery.d.ts index 41e19a0d57..ff24f291e5 100644 --- a/src/typings/jQuery.d.ts +++ b/src/typings/jQuery.d.ts @@ -4262,10 +4262,7 @@ declare namespace JQuery { stopPropagation(): void; } - interface Event extends Partial> { + interface Event { originalTarget?: TElement; originalEvent: _Event; new(event: string, properties?: T): JQuery.Event & T; diff --git a/src/typings/xterm.d.ts b/src/typings/xterm.d.ts index 3f1aecf853..695f872bcd 100644 --- a/src/typings/xterm.d.ts +++ b/src/typings/xterm.d.ts @@ -1043,38 +1043,3 @@ declare module 'xterm' { addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable; } } - - - - -// Modifications to official .d.ts below -declare module 'xterm' { - interface TerminalCore { - _onScroll: IEventEmitter; - _onKey: IEventEmitter<{ key: string }>; - - _charSizeService: { - width: number; - height: number; - }; - - _coreService: { - triggerDataEvent(data: string, wasUserInput?: boolean): void; - } - - _renderService: { - _renderer: { - _renderLayers: any[]; - }; - _onIntersectionChange: any; - }; - } - - interface IEventEmitter { - fire(e: T): void; - } - - interface Terminal { - _core: TerminalCore; - } -} diff --git a/src/vs/base/browser/dnd.ts b/src/vs/base/browser/dnd.ts index 23cc0ad948..bf7ea53494 100644 --- a/src/vs/base/browser/dnd.ts +++ b/src/vs/base/browser/dnd.ts @@ -111,4 +111,4 @@ export interface IStaticDND { export const StaticDND: IStaticDND = { CurrentDragAndDropData: undefined -}; \ No newline at end of file +}; diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 282581451f..27d56d5263 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -1193,7 +1193,7 @@ export function asDomUri(uri: URI): URI { return uri; } if (Schemas.vscodeRemote === uri.scheme) { - return RemoteAuthorities.rewrite(uri.authority, uri.path); + return RemoteAuthorities.rewrite(uri); } return uri; } diff --git a/src/vs/base/browser/markdownRenderer.ts b/src/vs/base/browser/markdownRenderer.ts index 73d71cd1aa..7d5a9ce197 100644 --- a/src/vs/base/browser/markdownRenderer.ts +++ b/src/vs/base/browser/markdownRenderer.ts @@ -14,6 +14,7 @@ import { parse } from 'vs/base/common/marshalling'; import { cloneAndChange } from 'vs/base/common/objects'; import { escape } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; +import { Schemas } from 'vs/base/common/network'; export interface MarkdownRenderOptions extends FormattedTextRenderOptions { codeBlockRenderer?: (modeId: string, value: string) => Promise; @@ -186,9 +187,9 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende renderer }; - const allowedSchemes = ['http', 'https', 'mailto', 'data']; + const allowedSchemes = [Schemas.http, Schemas.https, Schemas.mailto, Schemas.data, Schemas.file, Schemas.vscodeRemote]; if (markdown.isTrusted) { - allowedSchemes.push('command'); + allowedSchemes.push(Schemas.command); } const renderedMarkdown = marked.parse(markdown.value, markedOptions); diff --git a/src/vs/base/browser/ui/dialog/dialog.ts b/src/vs/base/browser/ui/dialog/dialog.ts index 27558b5b50..62e9a7bf95 100644 --- a/src/vs/base/browser/ui/dialog/dialog.ts +++ b/src/vs/base/browser/ui/dialog/dialog.ts @@ -55,13 +55,17 @@ export class Dialog extends Disposable { private buttonGroup: ButtonGroup | undefined; private styles: IDialogStyles | undefined; private focusToReturn: HTMLElement | undefined; + private checkboxHasFocus: boolean = false; + private buttons: string[]; - constructor(private container: HTMLElement, private message: string, private buttons: string[], private options: IDialogOptions) { + constructor(private container: HTMLElement, private message: string, buttons: string[], private options: IDialogOptions) { super(); this.modal = this.container.appendChild($(`.dialog-modal-block${options.type === 'pending' ? '.dimmed' : ''}`)); this.element = this.modal.appendChild($('.dialog-box')); hide(this.element); + // If no button is provided, default to OK + this.buttons = buttons.length ? buttons : [nls.localize('ok', "OK")]; const buttonsRowElement = this.element.appendChild($('.dialog-buttons-row')); this.buttonsContainer = buttonsRowElement.appendChild($('.dialog-buttons')); @@ -88,8 +92,6 @@ export class Dialog extends Disposable { checkboxMessageElement.innerText = this.options.checkboxLabel; } - - const toolbarRowElement = this.element.appendChild($('.dialog-toolbar-row')); this.toolbarContainer = toolbarRowElement.appendChild($('.dialog-toolbar')); } @@ -139,14 +141,27 @@ export class Dialog extends Disposable { let eventHandled = false; if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) { - focusedButton = focusedButton + buttonGroup.buttons.length - 1; - focusedButton = focusedButton % buttonGroup.buttons.length; - buttonGroup.buttons[focusedButton].focus(); + if (!this.checkboxHasFocus && focusedButton === 0) { + this.checkbox!.domNode.focus(); + this.checkboxHasFocus = true; + } else { + focusedButton = (this.checkboxHasFocus ? 0 : focusedButton) + buttonGroup.buttons.length - 1; + focusedButton = focusedButton % buttonGroup.buttons.length; + buttonGroup.buttons[focusedButton].focus(); + this.checkboxHasFocus = false; + } + eventHandled = true; } else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) { - focusedButton++; - focusedButton = focusedButton % buttonGroup.buttons.length; - buttonGroup.buttons[focusedButton].focus(); + if (!this.checkboxHasFocus && focusedButton === buttonGroup.buttons.length - 1) { + this.checkbox!.domNode.focus(); + this.checkboxHasFocus = true; + } else { + focusedButton = this.checkboxHasFocus ? 0 : focusedButton + 1; + focusedButton = focusedButton % buttonGroup.buttons.length; + buttonGroup.buttons[focusedButton].focus(); + this.checkboxHasFocus = false; + } eventHandled = true; } diff --git a/src/vs/base/browser/ui/grid/grid.ts b/src/vs/base/browser/ui/grid/grid.ts index e80e8042bb..b25e448c97 100644 --- a/src/vs/base/browser/ui/grid/grid.ts +++ b/src/vs/base/browser/ui/grid/grid.ts @@ -596,8 +596,8 @@ export class SerializableGrid extends Grid { super.layout(width, height); if (this.initialLayoutContext) { - this.gridview.trySet2x2(); this.initialLayoutContext = false; + this.gridview.trySet2x2(); } } } diff --git a/src/vs/base/browser/ui/grid/gridview.ts b/src/vs/base/browser/ui/grid/gridview.ts index d3784bed1e..8b38bcd655 100644 --- a/src/vs/base/browser/ui/grid/gridview.ts +++ b/src/vs/base/browser/ui/grid/gridview.ts @@ -250,6 +250,9 @@ class BranchNode implements ISplitView, IDisposable { const onDidSashReset = Event.map(this.splitview.onDidSashReset, i => [i]); this.splitviewSashResetDisposable = onDidSashReset(this._onDidSashReset.fire, this._onDidSashReset); + const onDidChildrenChange = Event.map(Event.any(...this.children.map(c => c.onDidChange)), () => undefined); + this.childrenChangeDisposable = onDidChildrenChange(this._onDidChange.fire, this._onDidChange); + const onDidChildrenSashReset = Event.any(...this.children.map((c, i) => Event.map(c.onDidSashReset, location => [i, ...location]))); this.childrenSashResetDisposable = onDidChildrenSashReset(this._onDidSashReset.fire, this._onDidSashReset); } @@ -422,7 +425,6 @@ class BranchNode implements ISplitView, IDisposable { } this.splitview.setViewVisible(index, visible); - this._onDidChange.fire(undefined); } getChildCachedVisibleSize(index: number): number | undefined { diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index 90f54f0e06..8c28a14567 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -27,11 +27,11 @@ export interface IIconLabelValueOptions { } class FastLabelNode { - private disposed: boolean; - private _textContent: string; - private _className: string; - private _title: string; - private _empty: boolean; + private disposed: boolean | undefined; + private _textContent: string | undefined; + private _className: string | undefined; + private _title: string | undefined; + private _empty: boolean | undefined; constructor(private _element: HTMLElement) { } @@ -89,7 +89,7 @@ export class IconLabel extends Disposable { private domNode: FastLabelNode; private labelDescriptionContainer: FastLabelNode; private labelNode: FastLabelNode | HighlightedLabel; - private descriptionNode: FastLabelNode | HighlightedLabel; + private descriptionNode: FastLabelNode | HighlightedLabel | undefined; private descriptionNodeFactory: () => FastLabelNode | HighlightedLabel; constructor(container: HTMLElement, options?: IIconLabelCreationOptions) { diff --git a/src/vs/base/browser/ui/inputbox/inputBox.css b/src/vs/base/browser/ui/inputbox/inputBox.css index 21ab84944d..9415d36a1b 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.css +++ b/src/vs/base/browser/ui/inputbox/inputBox.css @@ -64,6 +64,10 @@ outline: none; } +.monaco-inputbox > .wrapper > textarea.input.empty { + white-space: nowrap; +} + .monaco-inputbox > .wrapper > textarea.input::-webkit-scrollbar { display: none; } diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index d03467b8d3..d76ef39448 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -171,7 +171,7 @@ export class InputBox extends Widget { let tagName = this.options.flexibleHeight ? 'textarea' : 'input'; let wrapper = dom.append(this.element, $('.wrapper')); - this.input = dom.append(wrapper, $(tagName + '.input')); + this.input = dom.append(wrapper, $(tagName + '.input.empty')); this.input.setAttribute('autocorrect', 'off'); this.input.setAttribute('autocapitalize', 'off'); this.input.setAttribute('spellcheck', 'false'); @@ -242,13 +242,7 @@ export class InputBox extends Widget { }); } - setTimeout(() => { - if (!this.input) { - return; - } - - this.updateMirror(); - }, 0); + setTimeout(() => this.updateMirror(), 0); // Support actions if (this.options.actions) { @@ -270,21 +264,18 @@ export class InputBox extends Widget { } public setPlaceHolder(placeHolder: string): void { - if (this.input) { - this.input.setAttribute('placeholder', placeHolder); - this.input.title = placeHolder; - } + this.placeholder = placeHolder; + this.input.setAttribute('placeholder', placeHolder); + this.input.title = placeHolder; } public setAriaLabel(label: string): void { this.ariaLabel = label; - if (this.input) { - if (label) { - this.input.setAttribute('aria-label', this.ariaLabel); - } else { - this.input.removeAttribute('aria-label'); - } + if (label) { + this.input.setAttribute('aria-label', this.ariaLabel); + } else { + this.input.removeAttribute('aria-label'); } } @@ -550,6 +541,7 @@ export class InputBox extends Widget { this.validate(); this.updateMirror(); + dom.toggleClass(this.input, 'empty', !this.value); if (this.state === 'open' && this.contextViewProvider) { this.contextViewProvider.layout(); @@ -561,7 +553,7 @@ export class InputBox extends Widget { return; } - const value = this.value || this.placeholder; + const value = this.value; const lastCharCode = value.charCodeAt(value.length - 1); const suffix = lastCharCode === 10 ? ' ' : ''; const mirrorTextContent = value + suffix; @@ -594,20 +586,18 @@ export class InputBox extends Widget { } protected applyStyles(): void { - if (this.element) { - const background = this.inputBackground ? this.inputBackground.toString() : null; - const foreground = this.inputForeground ? this.inputForeground.toString() : null; - const border = this.inputBorder ? this.inputBorder.toString() : null; + const background = this.inputBackground ? this.inputBackground.toString() : null; + const foreground = this.inputForeground ? this.inputForeground.toString() : null; + const border = this.inputBorder ? this.inputBorder.toString() : null; - this.element.style.backgroundColor = background; - this.element.style.color = foreground; - this.input.style.backgroundColor = background; - this.input.style.color = foreground; + this.element.style.backgroundColor = background; + this.element.style.color = foreground; + this.input.style.backgroundColor = background; + this.input.style.color = foreground; - this.element.style.borderWidth = border ? '1px' : null; - this.element.style.borderStyle = border ? 'solid' : null; - this.element.style.borderColor = border; - } + this.element.style.borderWidth = border ? '1px' : null; + this.element.style.borderStyle = border ? 'solid' : null; + this.element.style.borderColor = border; } public layout(): void { @@ -625,16 +615,27 @@ export class InputBox extends Widget { } } + public insertAtCursor(text: string): void { + const inputElement = this.inputElement; + const start = inputElement.selectionStart; + const end = inputElement.selectionEnd; + const content = inputElement.value; + + if (start !== null && end !== null) { + this.value = content.substr(0, start) + text + content.substr(end); + inputElement.setSelectionRange(start + 1, start + 1); + this.layout(); + } + } + public dispose(): void { this._hideMessage(); - this.element = null!; // StrictNullOverride: nulling out ok in dispose - this.input = null!; // StrictNullOverride: nulling out ok in dispose - this.contextViewProvider = undefined; this.message = null; - this.validation = undefined; - this.state = null!; // StrictNullOverride: nulling out ok in dispose - this.actionbar = undefined; + + if (this.actionbar) { + this.actionbar.dispose(); + } super.dispose(); } diff --git a/src/vs/base/browser/ui/list/list.ts b/src/vs/base/browser/ui/list/list.ts index 2592a61c3c..3c6ac72122 100644 --- a/src/vs/base/browser/ui/list/list.ts +++ b/src/vs/base/browser/ui/list/list.ts @@ -105,3 +105,10 @@ export interface IListDragAndDrop { onDragOver(data: IDragAndDropData, targetElement: T | undefined, targetIndex: number | undefined, originalEvent: DragEvent): boolean | IListDragOverReaction; drop(data: IDragAndDropData, targetElement: T | undefined, targetIndex: number | undefined, originalEvent: DragEvent): void; } + +export class ListError extends Error { + + constructor(user: string, message: string) { + super(`ListError [${user}] ${message}`); + } +} diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index c8343521d9..f6dd11b08c 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -76,13 +76,14 @@ export class PagedList implements IDisposable { private _model!: IPagedModel; constructor( + user: string, container: HTMLElement, virtualDelegate: IListVirtualDelegate, renderers: IPagedRenderer[], options: IListOptions = {} ) { const pagedRenderers = renderers.map(r => new PagedRenderer>(r, () => this.model)); - this.list = new List(container, virtualDelegate, pagedRenderers, options); + this.list = new List(user, container, virtualDelegate, pagedRenderers, options); } getHTMLElement(): HTMLElement { diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 5054251c3d..9063a2466f 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { getOrDefault } from 'vs/base/common/objects'; -import { IDisposable, dispose, Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Gesture, EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch'; import * as DOM from 'vs/base/browser/dom'; import { Event, Emitter } from 'vs/base/common/event'; @@ -188,7 +188,7 @@ export class ListView implements ISpliceable, IDisposable { private currentDragFeedbackDisposable: IDisposable = Disposable.None; private onDragLeaveTimeout: IDisposable = Disposable.None; - private disposables: IDisposable[]; + private readonly disposables: DisposableStore = new DisposableStore(); private _onDidChangeContentHeight = new Emitter(); readonly onDidChangeContentHeight: Event = Event.latch(this._onDidChangeContentHeight.event); @@ -214,7 +214,7 @@ export class ListView implements ISpliceable, IDisposable { this.renderers.set(renderer.templateId, renderer); } - this.cache = new RowCache(this.renderers); + this.cache = this.disposables.add(new RowCache(this.renderers)); this.lastRenderTop = 0; this.lastRenderHeight = 0; @@ -238,18 +238,16 @@ export class ListView implements ISpliceable, IDisposable { this.rowsContainer.className = 'monaco-list-rows'; Gesture.addTarget(this.rowsContainer); - this.scrollableElement = new ScrollableElement(this.rowsContainer, { + this.scrollableElement = this.disposables.add(new ScrollableElement(this.rowsContainer, { alwaysConsumeMouseWheel: true, horizontal: this.horizontalScrolling ? ScrollbarVisibility.Auto : ScrollbarVisibility.Hidden, vertical: getOrDefault(options, o => o.verticalScrollMode, DefaultOptions.verticalScrollMode), useShadows: getOrDefault(options, o => o.useShadows, DefaultOptions.useShadows) - }); + })); this.domNode.appendChild(this.scrollableElement.getDomNode()); container.appendChild(this.domNode); - this.disposables = [this.rangeMap, this.scrollableElement, this.cache]; - this.scrollableElement.onScroll(this.onScroll, this, this.disposables); domEvent(this.rowsContainer, TouchEventType.Change)(this.onTouchChange, this, this.disposables); @@ -1178,6 +1176,6 @@ export class ListView implements ISpliceable, IDisposable { this.domNode.parentNode.removeChild(this.domNode); } - this.disposables = dispose(this.disposables); + dispose(this.disposables); } } diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 19b844bc13..7816dbe0c2 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -16,7 +16,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { Event, Emitter, EventBufferer } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; -import { IListVirtualDelegate, IListRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IIdentityProvider, IKeyboardNavigationLabelProvider, IListDragAndDrop, IListDragOverReaction, ListAriaRootRole } from './list'; +import { IListVirtualDelegate, IListRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IIdentityProvider, IKeyboardNavigationLabelProvider, IListDragAndDrop, IListDragOverReaction, ListAriaRootRole, ListError } from './list'; import { ListView, IListViewOptions, IListViewDragAndDrop, IAriaProvider } from './listView'; import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; @@ -862,7 +862,7 @@ export interface IListStyles { } const defaultStyles: IListStyles = { - listFocusBackground: Color.fromHex('#073655'), + listFocusBackground: Color.fromHex('#7FB0D0'), listActiveSelectionBackground: Color.fromHex('#0E639C'), listActiveSelectionForeground: Color.fromHex('#FFFFFF'), listFocusAndSelectionBackground: Color.fromHex('#094771'), @@ -1170,6 +1170,7 @@ export class List implements ISpliceable, IDisposable { readonly onDidDispose: Event = this._onDidDispose.event; constructor( + private user: string, container: HTMLElement, virtualDelegate: IListVirtualDelegate, renderers: IListRenderer[], @@ -1261,11 +1262,11 @@ export class List implements ISpliceable, IDisposable { splice(start: number, deleteCount: number, elements: T[] = []): void { if (start < 0 || start > this.view.length) { - throw new Error(`Invalid start index: ${start}`); + throw new ListError(this.user, `Invalid start index: ${start}`); } if (deleteCount < 0) { - throw new Error(`Invalid delete count: ${deleteCount}`); + throw new ListError(this.user, `Invalid delete count: ${deleteCount}`); } if (deleteCount === 0 && elements.length === 0) { @@ -1348,7 +1349,7 @@ export class List implements ISpliceable, IDisposable { setSelection(indexes: number[], browserEvent?: UIEvent): void { for (const index of indexes) { if (index < 0 || index >= this.length) { - throw new Error(`Invalid index ${index}`); + throw new ListError(this.user, `Invalid index ${index}`); } } @@ -1366,7 +1367,7 @@ export class List implements ISpliceable, IDisposable { setFocus(indexes: number[], browserEvent?: UIEvent): void { for (const index of indexes) { if (index < 0 || index >= this.length) { - throw new Error(`Invalid index ${index}`); + throw new ListError(this.user, `Invalid index ${index}`); } } @@ -1518,7 +1519,7 @@ export class List implements ISpliceable, IDisposable { reveal(index: number, relativeTop?: number): void { if (index < 0 || index >= this.length) { - throw new Error(`Invalid index ${index}`); + throw new ListError(this.user, `Invalid index ${index}`); } const scrollTop = this.view.getScrollTop(); @@ -1547,7 +1548,7 @@ export class List implements ISpliceable, IDisposable { */ getRelativeTop(index: number): number | null { if (index < 0 || index >= this.length) { - throw new Error(`Invalid index ${index}`); + throw new ListError(this.user, `Invalid index ${index}`); } const scrollTop = this.view.getScrollTop(); @@ -1574,7 +1575,7 @@ export class List implements ISpliceable, IDisposable { open(indexes: number[], browserEvent?: UIEvent): void { for (const index of indexes) { if (index < 0 || index >= this.length) { - throw new Error(`Invalid index ${index}`); + throw new ListError(this.user, `Invalid index ${index}`); } } @@ -1584,7 +1585,7 @@ export class List implements ISpliceable, IDisposable { pin(indexes: number[]): void { for (const index of indexes) { if (index < 0 || index >= this.length) { - throw new Error(`Invalid index ${index}`); + throw new ListError(this.user, `Invalid index ${index}`); } } diff --git a/src/vs/base/browser/ui/list/rangeMap.ts b/src/vs/base/browser/ui/list/rangeMap.ts index dc1fc0e591..450d0e3ccb 100644 --- a/src/vs/base/browser/ui/list/rangeMap.ts +++ b/src/vs/base/browser/ui/list/rangeMap.ts @@ -186,8 +186,4 @@ export class RangeMap { return -1; } - - dispose() { - this.groups = null!; // StrictNullOverride: nulling out ok in dispose - } } diff --git a/src/vs/base/browser/ui/list/rowCache.ts b/src/vs/base/browser/ui/list/rowCache.ts index 35256c7b24..0b4283cc74 100644 --- a/src/vs/base/browser/ui/list/rowCache.ts +++ b/src/vs/base/browser/ui/list/rowCache.ts @@ -79,11 +79,7 @@ export class RowCache implements IDisposable { return result; } - private garbageCollect(): void { - if (!this.renderers) { - return; - } - + dispose(): void { this.cache.forEach((cachedRows, templateId) => { for (const cachedRow of cachedRows) { const renderer = this.getRenderer(templateId); @@ -96,12 +92,6 @@ export class RowCache implements IDisposable { this.cache.clear(); } - dispose(): void { - this.garbageCollect(); - this.cache.clear(); - this.renderers = null!; // StrictNullOverride: nulling out ok in dispose - } - private getRenderer(templateId: string): IListRenderer { const renderer = this.renderers.get(templateId); if (!renderer) { @@ -109,4 +99,4 @@ export class RowCache implements IDisposable { } return renderer; } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/menu/menubar.ts b/src/vs/base/browser/ui/menu/menubar.ts index 3860b17388..cd25ca83f9 100644 --- a/src/vs/base/browser/ui/menu/menubar.ts +++ b/src/vs/base/browser/ui/menu/menubar.ts @@ -758,7 +758,7 @@ export class MenuBar extends Disposable { if (menuBarMenu.titleElement.children.length) { let child = menuBarMenu.titleElement.children.item(0) as HTMLElement; if (child) { - child.style.textDecoration = (this.options.alwaysOnMnemonics || visible) ? 'underline' : null; + child.style.textDecoration = (this.options.alwaysOnMnemonics || visible) ? 'underline' : ''; } } }); diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons-animations.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons-animations.css index 8818042c6e..265454bcd3 100644 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons-animations.css +++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons-animations.css @@ -10,5 +10,5 @@ } .octicon-animation-spin { - animation: octicon-spin 2s linear infinite; + animation: octicon-spin 1.5s linear infinite; } diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons-main.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons-main.css index 841e5e575c..46349b9f19 100644 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons-main.css +++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons-main.css @@ -10,10 +10,6 @@ body { font-family: var(--version) !important; } -body[data-octicons-update="enabled"] .monaco-workbench .part.statusbar > .items-container > .statusbar-item span.octicon { - font-size: 16px; -} - body[data-octicons-update="enabled"] .monaco-workbench .part.statusbar > .items-container > .statusbar-item > a { display: flex; align-items: center; diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css index 64ad6e37f6..7e86f3a74c 100644 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css +++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css @@ -1,7 +1,6 @@ @font-face { font-family: "octicons2"; - src: url("./octicons2.ttf?81972c7f658ef56eeefe672e514d35a3") format("truetype"), -url("./octicons2.svg?81972c7f658ef56eeefe672e514d35a3#octicons2") format("svg"); + src: url("./octicons2.ttf?90586c9ac0aa804395e9c9c0d15d1094") format("truetype"); } .octicon, .mega-octicon { @@ -247,5 +246,6 @@ body[data-octicons-update="enabled"] .octicon-warning:before { content: "\f02d" body[data-octicons-update="enabled"] .octicon-controls:before { content: "\26ad" } body[data-octicons-update="enabled"] .octicon-event:before { content: "\26ae" } body[data-octicons-update="enabled"] .octicon-record-keys:before { content: "\26af" } -body[data-octicons-update="enabled"] .octicon-archive:before { content: "\f101" } -body[data-octicons-update="enabled"] .octicon-arrow-both:before { content: "\f102" } +body[data-octicons-update="enabled"] .octicon-Vector:before { content: "\f101" } +body[data-octicons-update="enabled"] .octicon-archive:before { content: "\f102" } +body[data-octicons-update="enabled"] .octicon-arrow-both:before { content: "\f103" } diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.svg b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.svg deleted file mode 100644 index f80a5eab7f..0000000000 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.svg +++ /dev/null @@ -1,567 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf index 108574251ca4c2717b8c2e305741f37086d1b236..793aba95d5f9bc54ee6a037e5f5f86da874ea38d 100644 GIT binary patch delta 6375 zcmY+I3v^WFxrV=g@7a6LC3C-KGMQ^;?_4IyWG0gYC6f>|2th@Zi(mr?D7Bz~s7Qqo zM7-aa9?S85!L}l&0_o}T0L%8cY!~fmt=cY6TU)EG?V_%8>~CtVtCi%ue}1~!CV6J| z?3wxZp8dVw`+k$X4=bPTS02pOenZ6WC8DKkH?7%x&y7z$O=NqO$nCj$i=Q;Bxu>NY1{ViKR7*&_1-5^-racJ+BGY; z4DBcK{{;KCZd$W_Gy5_94BIihK7H+)P3zzJUG0yfM7!R_8?u|PyMEgpAHVh<(QX@& z{RU!0YVY(y+@2Q8s=pO`{^{qXnLXG$sjjH5^3MJfxzy9*6+e5bw)t=O)6>(V>TlHw z9@|L~d+{SydWn8W%wNy4P3+h82ifK7Q`6HEoV~8>SM2p~+k(xb@__0vsWV#z+&gi7 zM#-jz>fE-LsS}rJ-K@5nt!7)3aGcjnftM6q&RS=Y4?Y)1CAJJx+D{ z5~b)dx|zD^C`D;gjW$vP8KjX;yJ!JjMqek3()2GBq$}xOx`!%s4&`YN-A0{Mpj&7q zy-5E?SJQ6#8s+F3`aEr*JLuo3g&w9aQ-r=iMJiK?dTBX6@m7k_W@;ioJwk1?l&+#1 z=s&2LZl`DHIU1wdGJ2ZAbS|~izfuqN(T#LDxp1`|l%Ph6(-FFeMraN_NsH+iZJ`|$ zqOZ_()Jhl73OY<*r1L32w^EX}(K7j`!!_8`^L|yT7oXA`+K{?2LT7p85`K$ybBJ-dG#Uk@L3Cc$1S0pGP znO~Ejlw>|HK~c#(Btdz}{JNwzbAY3G08n!>k4aE{;@BmC4v0g00w{tw^eBKfh-(t4 zgt#t&UWgkKD2KRR0u2#&NT4R-PMjic2*M)nl0ag_8zc}Lakm7rBkqwve#FJXU}igj zZ2(ac4@w|U;voryN<1uqWQj*4G>A*YqY~(tIGS7lMH6q7&}!VLBv3i=v;=x5o|8cN z#9Jij0pg|v-9X%upf8BGO3)$1+d&OC^b|HaBxoDr1qm96c&9{I0Pm8Zsfc$=&|bug z5;Pj|9tm2Gcu9ihBVLxE4T<+k(2!K)a2Nr4lX#y5T}m8U5TIX)4@l6t#34cfdYJe* z5_B{1b0xG1_o6%i4NiPef>tLk$^+2!#6?MlghYjah9z(U;&UYM1mYtSxC3!fPXM1F zex3x5LHv9Pyo30tgwnX5CxM?3zd!J8CIs@1e@x>At6!A+Xuqxt9B`_`G%OtQb;>#s4GUAs@sJ0RtD>jRgaqJy#D$OmT#)!G3H*@wY6+Z?_!gS85*G&nFkRwjf&CKSD1i|Z-z0%06Temhb0)r70-HwvZ@~i~ zGK$|Ifp-(XQ34kyev<@#PJFur&QAP`5_mjuaajS}p7>4)e4n_`5kLZ<-6Y5Y;LPb4Jj&)=^q%xkh z?tjAnivM>3dtgtn7~C6*gsu!thVPFgBC8`)(LgPFMf8=JGd4T6Cw96q*?4W^PvYtL zE%75w&ZY~Rjwf0Y`x9?9E6ux-h2*;Asgx~MOf5~v(j)0zX`V@EuF4$Byqj&$uE?Iw zebQ2D`AW-c`H}pt{DJ&i`43Ig95J_=4_g6isdc*5*;;CSsV&m>M7yVbWBaN0&pHM= zYR`21w4fBuDQqts>&$ju+d0`)>e||My67twihGMc?dj`T-E*Yp^^#IbmiCn1FPF+U zmhUV-Qa)UMxmWKU?|r}0SJ_xORzYWwiZ2a|)Z6f-p#@P5JIY%XR_RhbYBMuDEEI{d zBrEmxGeb|RRfU;Vr4~&xJQ?(`tZA_>){AGu9v0SwrOcJzbxBMRR-I z8teOSd&uRD`_zV5bKL&@ssE*kVsL}Qn*O7@Pq|Ob4i09i{XwSgJM)Lq8|CBd&&s+p z52&oYW$Mq$;)!o1w1$hPzo&jd`2-V)OH3`nOw?~=EPpWL&uF=DE?f?mE9FXVT=_7S zIul4$l_O^sv74$VPvTGcB#m7u<-;>2<;9&RhEALqqI$6H=;@ zB<%LKXN-Nu#mydO>+4DRLgP0S{T-c_CpM>Lc%Z8@(b?@NUp!v&hQi6DnQO}jqOokI zwWU4V)^g>xTV_WR8XKtYSUGpO(_#~`!s2A}>K^xiIqSyWWV6;$ShHq%%eK4ia~HOz z*}0!jFIceR^Am4X%4#iwz$}aJE75W|iURg$Qc4(l%~_RR{G18-l~#R zExnmx)65#E&dI-MQ}3lx>^G4gIvVqDr>5>www!#snodvMl}Zf-b7;X_@cH1*mfk&V zpnsN@QVVIvYtbk3k;c^9Cr+IB%TQD5FDd*D#kz7KhBt(Q@#;`x{=~_XL=!K}I;|Lk zm|2(6y80ut&&g@1kVio|tBRTxx1vrShQFD8cvi3fb@r^bGry1f1A1|8Q!L_Y9dIVP z#a*x8qr^JdJJGob>~8C?_<}}#&ETN-<%VctZnqKi^$xVU*s=PHgN=w$5gOBb)x$7> zEKJ}M8n3@I*j@Kj(+v>G-;X!D+My_S)UT<=-6OG)zbzfm>-FkI?nh&Kz*p&Sb46l_ zkqKVCM^V#Mt?!zXj0>eXSeMcZnN?XSl9G4Pq+0*hoP6`B9`Q|`m^$u@xLgrmY-sLK zY{`;X6?guytFDc-sPn>Ry=x?@S?!%sniv}yHJDM~KmR=Y#{QP!?k2|Szns6SKDgjC zn^!l-&ez~eWxam=*c`3c=6=joKQY#eteoIuyEXOADL%37k{+9yBdh+kC1(9cOD?pH z@7ud?BDZvxQgh-`+@~H={)!lG!u-&K!Q=*fX+4a8qWl*cRnKL+6zGE`72Ps(Sv@@C zdi{OnQY0Mm;8XTRBc;CHE~bZAIh@OygAAQ06xCnWjhqM8Sr&~ILAQ1=VY50a8x6y0 zBhhlL%B)IN9b~6 zvns|g&Xd&F^hzA1kK<&(@ zTel_)?x^3%{K>Y+^)c6?P-2KFippN|wS^yzv?cv4Xpg#GE`MxiQwtL>^>{t z{OCQ{kxL+D@cuiSOl3=|puCZ)3_#9BT%(Q8=dua?7LwV>WQp03XyA62HD z_5I`X6lF>M7vrsUZPkjf3p4S6_+JGpp=A{~GIU?RVU<;XeAPVmZvA(wmI*b^Uj1ji z)J4N*69rYR0Ds0WR3lo(16AmdMx+eGnvtC!Dypx#I$g7ChH4m$8E%KoroHilNNdXH zOSSGO>^RuDy;>{0u(RVxL1xd;&MNzOs-bFAG}Z7s(hk4dhO(fzVP!Gi=bw7Buw&)H zj_p$x`_-C^Jgc>z`g-t@m#@=wYX&kW#^T z3qI264ZBqp!$W=3#@i?UwDDfOhOu<|4z$x-SmG7Jz`?Q*Y?qS5z+i-hxrJ8C z8a*{Vr<-EOxvV6X&`qnV_D4%1|Dy1ra>YEGj59m1Gc0mZ9sp;k<286@=14eBRu75Z zHVw8?g}9BTY~X@*-aua>tDcu@G_b3s6uZ@@hZ5y{NHLsxjXmAFYF0-bmeE8OWFrJvR;3bRZO_V&3IwgV>y*}Dw;4{==k|rF z9*3cZisLQzmdc!*<~15T@myn5qf52v?&fTFa&}Wk!fQAb#i=(sy>6cw2-nh@Gu*6a z73NkkAL-$#G1+x)SwnYtn+nlDII72-x}m6cr)C(Lh&k5e zXzPOu*zHD3ifs=He+shtC)@r|dtUvmasXY1{}%)etG^sIteHMRjr*fQ3RzUp%v%PM z#)3%ji{ltk)Vc%<-MO&mw(i@C^Yx|Yk6yBTY<_FGwB+)u*Dk%Z)T_hDx7fY-(%MDcdl}xa_Oivr zo}S|3{AgQyYwO(;ciebD$tFd6Ygx#3h=~ry`BhmtBj)FjN9jOC>LWJ~v&HqjH(!o1 z5VkP=iu!``624as*FU&9Rd?u56if71(fR{#J2 delta 6744 zcmc(jd6ZPuoyWiTy{dY(ch_FM)?U^7QdM2eB30NdDj-IKD1s;|gdiXSVKK%+L^O&K zEyq2sXcBcuq?2fr<4JNdBa_iAk|B#Eab_~c@#Hu+J;s^gNHgEtmt@9s=8u_k=ESc4 zy#3vG>;8WC`~AK8@NQ$zy~h4b{WpNv2Vm)y8&+*88oT(c+o{sJI0 z1ZOq8+PRdF@-IvX%#|PV;x%K1{M}H*DSU*OFThY|}Wt{+cUSE&Tb~9YEmQ zJho}WsvVoe&jqg+abA?%xN5`dU%g%b*ZIJ%t-K+<>6$HDecx$m26o>MIM+h}X8F`2 zF5gkja>*kf`FmmN2#>z7^67^zYdYf(@aSuQe!Ksd>Po#nHQ#*49O14L#_9W2OD~AG z*q26HY!Lt0*e{li|6Uw5?lx?V@7Y2fbM?c_D$J>^KCac+%!SPiHr}^gDU9)p?SrDe zQmho4#3r`41f!USd60zxD1Q15R0)HD{v{6<5A>rGar8+&c-cx1`p$IG|-8Mumc158lqTV$JOw_0UPZ2 z9L~Wf@t4RWfqM|dD%_6SP{wp*aU*u4554#-F2O-Ohc(!RFCmRjV=X>~z4$sZ_zT>N z2-aZ`MGT{ai{Qewh~XNvq8SgM3m0NFw&I&;#~wV616Y9iQapw*W}qAQV+bSo3@+wC zSsd#&#LHtL|07b*gMsf8PS~t2GP_ z@{em66y%@OFkHwV&@gbwKc!&^k$+mlU?Trz4a183S2PST^3P}(YUB^r)q)RJ4|ra~ z_#=Nv!%TqWX$5lvk~yegc0e*O70eSzyM`G9>CiBDAT15E2-2xxK0&%PsGr9T=BR>6 z2I;AkWfJTOida z5vmNNYKzng036edWOw1g4`d4Yyv1*tkkC|i(AH54$& zi!_un$cr@;HOOTu{>ym7CEPg;l@4;bhMEVdl7~?JAXV}Z?BaT*hKdMznTFa3dAWuv z38}supp`mg@Ua7&}IybJ;P);FNYbdOc>Vbq33#o1*6kABu7@_P!uG3I}Ayu3S zr5JL(hN29)K|^_l+^C^YLvA8!ur=c}Ls&7GPQjia7XeE#j zYiL}MU)0dTARpBz*O%&ngti8$I!kD9kWXl6b&yZ0p?H!f;#{k5LFj*w&uHj`kSYlY zJrVM28oDFo^BT38_Yp&^sYt($GaAU(wJ{A-|_VeJ3~mN<)){Jffl9LjH}0 z#tZp<4J{b*H4V)e@`oDQGUSgmG-${lYiQMwZ)j-RkViGNZ^)mh_;bNo2zg9HPlx=e zhVBmeGYx$n@)sI9KIEGkdOzfG4XXgiUuswnK>kX@$^h~$4Qm9*zt^x@sN?qnQ>ZfU z_orbAfeB`^g2eG>#$Js|t_fzi0+)0Bc@1k9Ox&(v6@!U=8rCzIV74n%Wy8Nb#q2uD?Li#D zukgNbi=>z#Hj4=(YwR+fFy1yFHeaz#vmLS>u}AIoKKq#cV*B;>BaSm14?5nl7Fma^ zpE=#m1pc5CN4yU2Ht!=o!?)OX(Dyrk z+JC+O!=^<|k2Ss1yrg-5U`b#{;Nie4!D+#_L)Fla!tLSbB8ww$MYGZGMvujku`k4q z#hvlR_4wE0@3zcnd93Akt!KAh-+HVq+_tw(wqM?Up#4W3i#kqp7CZ0le4}$Rkxjgv zY)&ppzLI<|RZd-(`daElx+nc&Zdz_@?%jMazc>Hg{P99-p;%Z~*jxB!;TK&?yB_TB z>t5Wwt^32CB|XP`7xg~V=jfZ!x2^9V`s4j${nz!s*k79%xMJYoU~zEs;Gv4T3ULk>?|)TuPkpW?=Ig{K0Z<&d8y*9j8$%}JTX2kyw=4z zVLoH*REFvj1#>hc%x6x1r~lO8yGFq{XHu9V(KGoU;@$CAJM7-`cyYh+0%gIYL{+4$ zKrA&HFjIk)y%Z@$GLg(kW~5~LPTrYF7}q9iCx2iRCy!JQALhUDLP8%tdC(};Uar0T za;?$U^ZabKdG+ZwoA~mTiUq7xArNAlVk8xL)3`RF?yDN5ldp?!PQLn)W+q>))yBQO z=ez4SnCBWFP-ZBrVn7t~gCcJ^PJbfd*l;)@BGH5hCyYp^2&*&cd|{Z^*)o5;E)woE zW6{y77_E#}Mk)o%Z&-d&7_g0$E2G0a80$1j#j080jrqcWF`8G`4p&B_v1mQUg%!2T zq2$$x4w3WuGKv07HX0H(yCDpx&DCTWcALXxd2MdH-QjlH`YfjzZSuQZE&a8HJu8;? zo|~K<_Zsbeu3RZGeC=qqR?3BaUc+uWyzRM2Fx}!8mfhiUTP`-~Yp!G>F?)Nq+TRuz zqV5rw&0RCMIxi=LttpgF_4f`~;jra%nx+vnEq}~ry4-HlWjgF$%jpS+eNM~Pk#0+* zv;9jJ%`XWdm-vui4ky z;m;=1CBMryx4L*{-?UNN8QC<(cUMYgy^E?dq)Htzs1u|xk_n_Du~H-&8!=Obk_wwYOUHL^?dY;3{ObFJ*|y?baV;}0#p!KiaI zPJM~;^Z{M4h3}c?)6VZ;9r-BB_HW^*^gh4n7Zp(x=Za-wySPgn6t9b8;@3<*ztL$_ z#YlO;u!;<%F~IFgEaNw05l1u@2}fs&Xw{e{s-iGb88A%dq%l)eI*ksIiG-O7nRGor zOIR6x4T@U1!jq$!wBPuz`$Z-iV;Y~np;tsoRiPRjRZq=@9qGKvW_z(x&ZiyWXyO0b zrTYKSr$1+x>i@f8`v2{cct2n3Xc}2Kzb91B477w2O;%ej6UkonP^7D~Ss1ytzQpCt z9WhT^R)}D-=a-f*=)TV#@;j@hX*bu{ojW$$Em3U`pYM)uiFPLfLgZTe5}OV4b1~1d zaQoC{*KF?WZOw{6XV;{Cbnz(v#k~c!8a?`_$7kvv@8bvRfBtW8d?0$}FR1uCYWes; zJrk})GPyR(pA5C+ejx&huIN*3UE=OUpYTRIn)ZvXwx?no;mLn`)*bL$!t#aO&;F1; zXV9sB_@L8%a9_AR(;i54M{jA%8=H9F``i!jJIF|JcJ?MV8TqzbqFsr=XA6}IM}Lo6 zEUuiG>P205<74YZU3cSS>xEMf27hHKE#G6$^5uA8&4Ef%F!In+8K zGHG>9lSma=2A*!U%DZ`gr9N6I4+x=^J?t>vo4aL>W%=7%dUFGXBp>T`S}xOaSq_KO z>-UHKA-C62PG#C#+^oc$O#y$<)9VQ}N8|BWpve_z3#W%F;egW-X^w=d(I$_@+D>e5 zd}3)Z&>lC8j=o^1Gu4p}#pY}|xy~1?2U|lSOK3yD=(No(%%yGdn|{| zVYys3Q)C^Mw<*$^%=LSkO~Y>Z+|7Qg$;LV|VsnIAf|lJIbowIc_FQK=9t*jhKDXCZ z9KEK{+m%Zu+q#`iLCfX#qzX50nLGKadR}W#RV94aJat=R{g*BVpf4AluiSxx@Wrhy9<}j?kRaX=d7CEcg}Fc z)165T*5(XtvF)E&nt8za>EfBSp>($=Qaq=B`l>k{o?WR#Ks_ diff --git a/src/vs/base/browser/ui/progressbar/progressbar.ts b/src/vs/base/browser/ui/progressbar/progressbar.ts index d394e08ef7..da1f7fe5c6 100644 --- a/src/vs/base/browser/ui/progressbar/progressbar.ts +++ b/src/vs/base/browser/ui/progressbar/progressbar.ts @@ -36,8 +36,8 @@ const defaultOpts = { export class ProgressBar extends Disposable { private options: IProgressBarOptions; private workedVal: number; - private element: HTMLElement; - private bit: HTMLElement; + private element!: HTMLElement; + private bit!: HTMLElement; private totalWork: number | undefined; private progressBarBackground: Color | undefined; private showDelayedScheduler: RunOnceScheduler; @@ -232,4 +232,4 @@ export class ProgressBar extends Disposable { this.bit.style.backgroundColor = background; } } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index ae0c57058d..691d59bbb6 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -143,7 +143,7 @@ export class Sash extends Disposable { this._register(domEvent(this.el, EventType.Start)(this.onTouchStart, this)); if (isIPad) { - // see also http://ux.stackexchange.com/questions/39023/what-is-the-optimum-button-size-of-touch-screen-applications + // see also https://ux.stackexchange.com/questions/39023/what-is-the-optimum-button-size-of-touch-screen-applications addClass(this.el, 'touch'); } @@ -179,27 +179,8 @@ export class Sash extends Disposable { let isMultisashResize = false; - if (this.linkedSash && !(e as any).__linkedSashEvent) { - (e as any).__linkedSashEvent = true; - this.linkedSash.onMouseDown(e); - } - if (!(e as any).__orthogonalSashEvent) { - let orthogonalSash: Sash | undefined; - - if (this.orientation === Orientation.VERTICAL) { - if (e.offsetY <= 4) { - orthogonalSash = this.orthogonalStartSash; - } else if (e.offsetY >= this.el.clientHeight - 4) { - orthogonalSash = this.orthogonalEndSash; - } - } else { - if (e.offsetX <= 4) { - orthogonalSash = this.orthogonalStartSash; - } else if (e.offsetX >= this.el.clientWidth - 4) { - orthogonalSash = this.orthogonalEndSash; - } - } + const orthogonalSash = this.getOrthogonalSash(e); if (orthogonalSash) { isMultisashResize = true; @@ -208,6 +189,11 @@ export class Sash extends Disposable { } } + if (this.linkedSash && !(e as any).__linkedSashEvent) { + (e as any).__linkedSashEvent = true; + this.linkedSash.onMouseDown(e); + } + if (!this.state) { return; } @@ -295,7 +281,17 @@ export class Sash extends Disposable { domEvent(window, 'mouseup')(onMouseUp, null, disposables); } - private onMouseDoubleClick(event: MouseEvent): void { + private onMouseDoubleClick(e: MouseEvent): void { + const orthogonalSash = this.getOrthogonalSash(e); + + if (orthogonalSash) { + orthogonalSash._onDidReset.fire(); + } + + if (this.linkedSash) { + this.linkedSash._onDidReset.fire(); + } + this._onDidReset.fire(); } @@ -386,13 +382,26 @@ export class Sash extends Disposable { toggleClass(this.el, 'orthogonal-end', state !== SashState.Disabled); } - dispose(): void { - super.dispose(); - - if (this.el && this.el.parentElement) { - this.el.parentElement.removeChild(this.el); + private getOrthogonalSash(e: MouseEvent): Sash | undefined { + if (this.orientation === Orientation.VERTICAL) { + if (e.offsetY <= 4) { + return this.orthogonalStartSash; + } else if (e.offsetY >= this.el.clientHeight - 4) { + return this.orthogonalEndSash; + } + } else { + if (e.offsetX <= 4) { + return this.orthogonalStartSash; + } else if (e.offsetX >= this.el.clientWidth - 4) { + return this.orthogonalEndSash; + } } - this.el = null!; // StrictNullOverride: nulling out ok in dispose + return undefined; + } + + dispose(): void { + super.dispose(); + this.el.remove(); } } diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index 936d83f9df..7077adb5bc 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -737,7 +737,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi this.listRenderer = new SelectListRenderer(); - this.selectList = new List(this.selectDropDownListContainer, this, [this.listRenderer], { + this.selectList = new List('SelectBoxCustom', this.selectDropDownListContainer, this, [this.listRenderer], { ariaLabel: this.selectBoxOptions.ariaLabel, useShadows: false, verticalScrollMode: ScrollbarVisibility.Visible, diff --git a/src/vs/base/browser/ui/splitview/splitview.css b/src/vs/base/browser/ui/splitview/splitview.css index 1a43420662..87cb31b5ca 100644 --- a/src/vs/base/browser/ui/splitview/splitview.css +++ b/src/vs/base/browser/ui/splitview/splitview.css @@ -21,24 +21,15 @@ } .monaco-split-view2 > .split-view-container { - display: flex; width: 100%; height: 100%; white-space: nowrap; -} - -.monaco-split-view2.vertical > .split-view-container { - flex-direction: column; -} - -.monaco-split-view2.horizontal > .split-view-container { - flex-direction: row; + position: relative; } .monaco-split-view2 > .split-view-container > .split-view-view { white-space: initial; - flex: none; - position: relative; + position: absolute; } .monaco-split-view2 > .split-view-container > .split-view-view:not(.visible) { @@ -51,7 +42,6 @@ .monaco-split-view2.horizontal > .split-view-container > .split-view-view { height: 100%; - display: inline-block; } .monaco-split-view2.separator-border > .split-view-container > .split-view-view:not(:first-child)::before { diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 8f74bc3637..c6e34af059 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -125,15 +125,13 @@ abstract class ViewItem { } } - layout(_orthogonalSize: number | undefined): void { - this.container.scrollTop = 0; - this.container.scrollLeft = 0; - } - - layoutView(orthogonalSize: number | undefined): void { + layout(position: number, orthogonalSize: number | undefined): void { + this.layoutContainer(position); this.view.layout(this.size, orthogonalSize); } + abstract layoutContainer(position: number): void; + dispose(): IView { this.disposable.dispose(); return this.view; @@ -142,19 +140,17 @@ abstract class ViewItem { class VerticalViewItem extends ViewItem { - layout(orthogonalSize: number | undefined): void { - super.layout(orthogonalSize); + layoutContainer(position: number): void { + this.container.style.top = `${position}px`; this.container.style.height = `${this.size}px`; - this.layoutView(orthogonalSize); } } class HorizontalViewItem extends ViewItem { - layout(orthogonalSize: number | undefined): void { - super.layout(orthogonalSize); + layoutContainer(position: number): void { + this.container.style.left = `${position}px`; this.container.style.width = `${this.size}px`; - this.layoutView(orthogonalSize); } } @@ -853,7 +849,12 @@ export class SplitView extends Disposable { this.contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); // Layout views - this.viewItems.forEach(item => item.layout(this.orthogonalSize)); + let position = 0; + + for (const viewItem of this.viewItems) { + viewItem.layout(position, this.orthogonalSize); + position += viewItem.size; + } // Layout sashes this.sashItems.forEach(item => item.sash.layout()); @@ -910,7 +911,7 @@ export class SplitView extends Disposable { position += this.viewItems[i].size; if (this.sashItems[i].sash === sash) { - return position; + return Math.min(position, this.contentSize - 2); } } diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 5204ced912..a0705e5062 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -98,9 +98,11 @@ class TreeNodeListDragAndDrop implements IListDragAndDrop< } if (result.bubble === TreeDragOverBubble.Up) { - const parentNode = targetNode.parent; const model = this.modelProvider(); - const parentIndex = parentNode && model.getListIndex(model.getNodeLocation(parentNode)); + const ref = model.getNodeLocation(targetNode); + const parentRef = model.getParentNodeLocation(ref); + const parentNode = model.getNode(parentRef); + const parentIndex = parentRef && model.getListIndex(parentRef); return this.onDragOver(data, parentNode, parentIndex, originalEvent, false); } @@ -155,7 +157,12 @@ function asListOptions(modelProvider: () => ITreeModel implements Collection { } } -class TreeRenderer implements IListRenderer, ITreeListTemplateData> { +class TreeRenderer implements IListRenderer, ITreeListTemplateData> { private static DefaultIndent = 8; @@ -251,6 +258,7 @@ class TreeRenderer implements IListRenderer, + private modelProvider: () => ITreeModel, onDidChangeCollapseState: Event>, private activeNodes: Collection>, options: ITreeRendererOptions = {} @@ -381,10 +389,19 @@ class TreeRenderer implements IListRenderer('.indent-guide', { style: `width: ${this.indent}px` }); if (this.activeIndentNodes.has(parent)) { @@ -412,12 +429,16 @@ class TreeRenderer implements IListRenderer>(); + const model = this.modelProvider(); nodes.forEach(node => { + const ref = model.getNodeLocation(node); + const parentRef = model.getParentNodeLocation(ref); + if (node.collapsible && node.children.length > 0 && !node.collapsed) { set.add(node); - } else if (node.parent) { - set.add(node.parent); + } else if (parentRef) { + set.add(model.getNode(parentRef)); } }); @@ -1053,13 +1074,15 @@ class TreeNodeListMouseController extends MouseController< return super.onPointer(e); } - const model = ((this.tree as any).model as ITreeModel); // internal - const location = model.getNodeLocation(node); - const recursive = e.browserEvent.altKey; - model.setCollapsed(location, undefined, recursive); + if (node.collapsible) { + const model = ((this.tree as any).model as ITreeModel); // internal + const location = model.getNodeLocation(node); + const recursive = e.browserEvent.altKey; + model.setCollapsed(location, undefined, recursive); - if (expandOnlyOnTwistieClick && onTwistie) { - return; + if (expandOnlyOnTwistieClick && onTwistie) { + return; + } } super.onPointer(e); @@ -1087,6 +1110,7 @@ interface ITreeNodeListOptions extends IListOptions extends List> { constructor( + user: string, container: HTMLElement, virtualDelegate: IListVirtualDelegate>, renderers: IListRenderer[], @@ -1094,7 +1118,7 @@ class TreeNodeList extends List> private selectionTrait: Trait, options: ITreeNodeListOptions ) { - super(container, virtualDelegate, renderers, options); + super(user, container, virtualDelegate, renderers, options); } protected createMouseController(options: ITreeNodeListOptions): MouseController> { @@ -1150,7 +1174,7 @@ class TreeNodeList extends List> export abstract class AbstractTree implements IDisposable { protected view: TreeNodeList; - private renderers: TreeRenderer[]; + private renderers: TreeRenderer[]; protected model: ITreeModel; private focus: Trait; private selection: Trait; @@ -1195,6 +1219,7 @@ export abstract class AbstractTree implements IDisposable get onDidDispose(): Event { return this.view.onDidDispose; } constructor( + user: string, container: HTMLElement, delegate: IListVirtualDelegate, renderers: ITreeRenderer[], @@ -1207,7 +1232,7 @@ export abstract class AbstractTree implements IDisposable const activeNodes = new EventCollection(onDidChangeActiveNodes.event); this.disposables.push(activeNodes); - this.renderers = renderers.map(r => new TreeRenderer(r, onDidChangeCollapseStateRelay.event, activeNodes, _options)); + this.renderers = renderers.map(r => new TreeRenderer(r, () => this.model, onDidChangeCollapseStateRelay.event, activeNodes, _options)); this.disposables.push(...this.renderers); let filter: TypeFilter | undefined; @@ -1220,9 +1245,9 @@ export abstract class AbstractTree implements IDisposable this.focus = new Trait(_options.identityProvider); this.selection = new Trait(_options.identityProvider); - this.view = new TreeNodeList(container, treeDelegate, this.renderers, this.focus, this.selection, { ...asListOptions(() => this.model, _options), tree: this }); + this.view = new TreeNodeList(user, container, treeDelegate, this.renderers, this.focus, this.selection, { ...asListOptions(() => this.model, _options), tree: this }); - this.model = this.createModel(this.view, _options); + this.model = this.createModel(user, this.view, _options); onDidChangeCollapseStateRelay.input = this.model.onDidChangeCollapseState; this.model.onDidSplice(e => { @@ -1379,7 +1404,9 @@ export abstract class AbstractTree implements IDisposable // Tree navigation getParentElement(location: TRef): T { - return this.model.getParentElement(location); + const parentRef = this.model.getParentNodeLocation(location); + const parentNode = this.model.getNode(parentRef); + return parentNode.element; } getFirstElementChild(location: TRef): T | undefined { @@ -1416,6 +1443,10 @@ export abstract class AbstractTree implements IDisposable return this.model.isCollapsible(location); } + setCollapsible(location: TRef, collapsible?: boolean): boolean { + return this.model.setCollapsible(location, collapsible); + } + isCollapsed(location: TRef): boolean { return this.model.isCollapsed(location); } @@ -1531,7 +1562,7 @@ export abstract class AbstractTree implements IDisposable if (!didChange) { const parentLocation = this.model.getParentNodeLocation(location); - if (parentLocation === null) { + if (!parentLocation) { return; } @@ -1586,7 +1617,7 @@ export abstract class AbstractTree implements IDisposable this.model.setCollapsed(location, undefined, recursive); } - protected abstract createModel(view: ISpliceable>, options: IAbstractTreeOptions): ITreeModel; + protected abstract createModel(user: string, view: ISpliceable>, options: IAbstractTreeOptions): ITreeModel; navigate(start?: TRef): ITreeNavigator { return new TreeNavigator(this.view, this.model, start); @@ -1633,22 +1664,6 @@ class TreeNavigator, TFilterData, TRef> implements IT return this.current(); } - parent(): T | null { - if (this.index < 0 || this.index >= this.view.length) { - return null; - } - - const node = this.view.element(this.index); - - if (!node.parent) { - this.index = -1; - return this.current(); - } - - this.index = this.model.getListIndex(this.model.getNodeLocation(node.parent)); - return this.current(); - } - first(): T | null { this.index = 0; return this.current(); diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 14580cd07c..2b56371210 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { ComposedTreeDelegate, IAbstractTreeOptions, IAbstractTreeOptionsUpdate } from 'vs/base/browser/ui/tree/abstractTree'; -import { ObjectTree, IObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTree'; +import { ObjectTree, IObjectTreeOptions, CompressibleObjectTree, ICompressibleTreeRenderer } from 'vs/base/browser/ui/tree/objectTree'; import { IListVirtualDelegate, IIdentityProvider, IListDragAndDrop, IListDragOverReaction } from 'vs/base/browser/ui/list/list'; -import { ITreeElement, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeSorter, ICollapseStateChangeEvent, IAsyncDataSource, ITreeDragAndDrop } from 'vs/base/browser/ui/tree/tree'; +import { ITreeElement, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeSorter, ICollapseStateChangeEvent, IAsyncDataSource, ITreeDragAndDrop, TreeError, WeakMapper } from 'vs/base/browser/ui/tree/tree'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Emitter, Event } from 'vs/base/common/event'; import { timeout, CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; @@ -18,13 +18,14 @@ import { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors import { toggleClass } from 'vs/base/browser/dom'; import { values } from 'vs/base/common/map'; import { ScrollEvent } from 'vs/base/common/scrollable'; +import { ICompressedTreeNode, ICompressedTreeElement } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; interface IAsyncDataTreeNode { element: TInput | T; readonly parent: IAsyncDataTreeNode | null; readonly children: IAsyncDataTreeNode[]; readonly id?: string | null; - loading: boolean; + refreshPromise: Promise | undefined; hasChildren: boolean; stale: boolean; slow: boolean; @@ -41,7 +42,7 @@ function createAsyncDataTreeNode(props: IAsyncDataTreeNodeRequiredPro return { ...props, children: [], - loading: false, + refreshPromise: undefined, stale: true, slow: false, collapsedByDefault: undefined @@ -66,10 +67,11 @@ interface IDataTreeListTemplateData { templateData: T; } +type AsyncDataTreeNodeMapper = WeakMapper | null, TFilterData>, ITreeNode>; + class AsyncDataTreeNodeWrapper implements ITreeNode { get element(): T { return this.node.element!.element as T; } - get parent(): ITreeNode | undefined { return this.node.parent && new AsyncDataTreeNodeWrapper(this.node.parent); } get children(): ITreeNode[] { return this.node.children.map(node => new AsyncDataTreeNodeWrapper(node)); } get depth(): number { return this.node.depth; } get visibleChildrenCount(): number { return this.node.visibleChildrenCount; } @@ -82,14 +84,15 @@ class AsyncDataTreeNodeWrapper implements ITreeNode | null, TFilterData>) { } } -class DataTreeRenderer implements ITreeRenderer, TFilterData, IDataTreeListTemplateData> { +class AsyncDataTreeRenderer implements ITreeRenderer, TFilterData, IDataTreeListTemplateData> { readonly templateId: string; private renderedNodes = new Map, IDataTreeListTemplateData>(); private disposables: IDisposable[] = []; constructor( - private renderer: ITreeRenderer, + protected renderer: ITreeRenderer, + protected nodeMapper: AsyncDataTreeNodeMapper, readonly onDidChangeTwistieState: Event> ) { this.templateId = renderer.templateId; @@ -101,7 +104,7 @@ class DataTreeRenderer implements ITreeRe } renderElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void { - this.renderer.renderElement(new AsyncDataTreeNodeWrapper(node), index, templateData.templateData, height); + this.renderer.renderElement(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height); } renderTwistie(element: IAsyncDataTreeNode, twistieElement: HTMLElement): boolean { @@ -111,7 +114,7 @@ class DataTreeRenderer implements ITreeRe disposeElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void { if (this.renderer.disposeElement) { - this.renderer.disposeElement(new AsyncDataTreeNodeWrapper(node), index, templateData.templateData, height); + this.renderer.disposeElement(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height); } } @@ -243,25 +246,6 @@ function asObjectTreeOptions(options?: IAsyncDataTreeOpt }; } -function asTreeElement(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): ITreeElement> { - let collapsed: boolean | undefined; - - if (viewStateContext && viewStateContext.viewState.expanded && node.id && viewStateContext.viewState.expanded.indexOf(node.id) > -1) { - collapsed = false; - } else { - collapsed = node.collapsedByDefault; - } - - node.collapsedByDefault = undefined; - - return { - element: node, - children: node.hasChildren ? Iterator.map(Iterator.fromArray(node.children), child => asTreeElement(child, viewStateContext)) : [], - collapsible: node.hasChildren, - collapsed - }; -} - export interface IAsyncDataTreeOptionsUpdate extends IAbstractTreeOptionsUpdate { } export interface IAsyncDataTreeOptions extends IAsyncDataTreeOptionsUpdate, Pick, Exclude, 'collapseByDefault'>> { @@ -304,7 +288,9 @@ export class AsyncDataTree implements IDisposable private readonly autoExpandSingleChildren: boolean; private readonly _onDidRender = new Emitter(); - private readonly _onDidChangeNodeSlowState = new Emitter>(); + protected readonly _onDidChangeNodeSlowState = new Emitter>(); + + protected readonly nodeMapper: AsyncDataTreeNodeMapper = new WeakMapper(node => new AsyncDataTreeNodeWrapper(node)); protected readonly disposables: IDisposable[] = []; @@ -339,6 +325,7 @@ export class AsyncDataTree implements IDisposable get onDidDispose(): Event { return this.tree.onDidDispose; } constructor( + private user: string, container: HTMLElement, delegate: IListVirtualDelegate, renderers: ITreeRenderer[], @@ -350,11 +337,7 @@ export class AsyncDataTree implements IDisposable this.sorter = options.sorter; this.collapseByDefault = options.collapseByDefault; - const objectTreeDelegate = new ComposedTreeDelegate>(delegate); - const objectTreeRenderers = renderers.map(r => new DataTreeRenderer(r, this._onDidChangeNodeSlowState.event)); - const objectTreeOptions = asObjectTreeOptions(options) || {}; - - this.tree = new ObjectTree(container, objectTreeDelegate, objectTreeRenderers, objectTreeOptions); + this.tree = this.createTree(user, container, delegate, renderers, options); this.root = createAsyncDataTreeNode({ element: undefined!, @@ -374,6 +357,20 @@ export class AsyncDataTree implements IDisposable this.tree.onDidChangeCollapseState(this._onDidChangeCollapseState, this, this.disposables); } + protected createTree( + user: string, + container: HTMLElement, + delegate: IListVirtualDelegate, + renderers: ITreeRenderer[], + options: IAsyncDataTreeOptions + ): ObjectTree, TFilterData> { + const objectTreeDelegate = new ComposedTreeDelegate>(delegate); + const objectTreeRenderers = renderers.map(r => new AsyncDataTreeRenderer(r, this.nodeMapper, this._onDidChangeNodeSlowState.event)); + const objectTreeOptions = asObjectTreeOptions(options) || {}; + + return new ObjectTree(user, container, objectTreeDelegate, objectTreeRenderers, objectTreeOptions); + } + updateOptions(options: IAsyncDataTreeOptionsUpdate = {}): void { this.tree.updateOptions(options); } @@ -450,7 +447,7 @@ export class AsyncDataTree implements IDisposable const viewStateContext = viewState && { viewState, focus: [], selection: [] } as IAsyncDataTreeViewStateContext; - await this.updateChildren(input, true, viewStateContext); + await this._updateChildren(input, true, viewStateContext); if (viewStateContext) { this.tree.setFocus(viewStateContext.focus); @@ -462,13 +459,17 @@ export class AsyncDataTree implements IDisposable } } - async updateChildren(element: TInput | T = this.root.element, recursive = true, viewStateContext?: IAsyncDataTreeViewStateContext): Promise { + async updateChildren(element: TInput | T = this.root.element, recursive = true): Promise { + await this._updateChildren(element, recursive); + } + + private async _updateChildren(element: TInput | T = this.root.element, recursive = true, viewStateContext?: IAsyncDataTreeViewStateContext): Promise { if (typeof this.root.element === 'undefined') { - throw new Error('Tree input not set'); + throw new TreeError(this.user, 'Tree input not set'); } - if (this.root.loading) { - await this.subTreeRefreshPromises.get(this.root)!; + if (this.root.refreshPromise) { + await this.root.refreshPromise; await Event.toPromise(this._onDidRender.event); } @@ -505,7 +506,7 @@ export class AsyncDataTree implements IDisposable getNode(element: TInput | T = this.root.element): ITreeNode { const dataNode = this.getDataNode(element); const node = this.tree.getNode(dataNode === this.root ? null : dataNode); - return new AsyncDataTreeNodeWrapper(node); + return this.nodeMapper.map(node); } collapse(element: T, recursive: boolean = false): boolean { @@ -515,24 +516,29 @@ export class AsyncDataTree implements IDisposable async expand(element: T, recursive: boolean = false): Promise { if (typeof this.root.element === 'undefined') { - throw new Error('Tree input not set'); + throw new TreeError(this.user, 'Tree input not set'); } - if (this.root.loading) { - await this.subTreeRefreshPromises.get(this.root)!; + if (this.root.refreshPromise) { + await this.root.refreshPromise; await Event.toPromise(this._onDidRender.event); } const node = this.getDataNode(element); - if (node !== this.root && !node.loading && !this.tree.isCollapsed(node)) { + if (node.refreshPromise) { + await this.root.refreshPromise; + await Event.toPromise(this._onDidRender.event); + } + + if (node !== this.root && !node.refreshPromise && !this.tree.isCollapsed(node)) { return false; } const result = this.tree.expand(node === this.root ? null : node, recursive); - if (node.loading) { - await this.subTreeRefreshPromises.get(node)!; + if (node.refreshPromise) { + await this.root.refreshPromise; await Event.toPromise(this._onDidRender.event); } @@ -643,7 +649,7 @@ export class AsyncDataTree implements IDisposable const node: IAsyncDataTreeNode | undefined = this.nodes.get((element === this.root.element ? null : element) as T); if (!node) { - throw new Error(`Data tree node not found: ${element}`); + throw new TreeError(this.user, `Data tree node not found: ${element}`); } return node; @@ -676,18 +682,18 @@ export class AsyncDataTree implements IDisposable return result; } - result = this.doRefreshSubTree(node, recursive, viewStateContext); - this.subTreeRefreshPromises.set(node, result); - - try { - await result; - } finally { - this.subTreeRefreshPromises.delete(node); - } + return this.doRefreshSubTree(node, recursive, viewStateContext); } private async doRefreshSubTree(node: IAsyncDataTreeNode, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext): Promise { - node.loading = true; + let done: () => void; + node.refreshPromise = new Promise(c => done = c); + this.subTreeRefreshPromises.set(node, node.refreshPromise); + + node.refreshPromise.finally(() => { + node.refreshPromise = undefined; + this.subTreeRefreshPromises.delete(node); + }); try { const childrenToRefresh = await this.doRefreshNode(node, recursive, viewStateContext); @@ -695,7 +701,7 @@ export class AsyncDataTree implements IDisposable await Promise.all(childrenToRefresh.map(child => this.doRefreshSubTree(child, recursive, viewStateContext))); } finally { - node.loading = false; + done!(); } } @@ -866,16 +872,40 @@ export class AsyncDataTree implements IDisposable } private render(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): void { - const children = node.children.map(c => asTreeElement(c, viewStateContext)); + const children = node.children.map(node => this.asTreeElement(node, viewStateContext)); this.tree.setChildren(node === this.root ? null : node, children); + + if (node !== this.root) { + this.tree.setCollapsible(node, node.hasChildren); + } + this._onDidRender.fire(); } + protected asTreeElement(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): ITreeElement> { + let collapsed: boolean | undefined; + + if (viewStateContext && viewStateContext.viewState.expanded && node.id && viewStateContext.viewState.expanded.indexOf(node.id) > -1) { + collapsed = false; + } else { + collapsed = node.collapsedByDefault; + } + + node.collapsedByDefault = undefined; + + return { + element: node, + children: node.hasChildren ? Iterator.map(Iterator.fromArray(node.children), child => this.asTreeElement(child, viewStateContext)) : [], + collapsible: node.hasChildren, + collapsed + }; + } + // view state getViewState(): IAsyncDataTreeViewState { if (!this.identityProvider) { - throw new Error('Can\'t get tree view state without an identity provider'); + throw new TreeError(this.user, 'Can\'t get tree view state without an identity provider'); } const getId = (element: T) => this.identityProvider!.getId(element).toString(); @@ -903,3 +933,117 @@ export class AsyncDataTree implements IDisposable dispose(this.disposables); } } + +type CompressibleAsyncDataTreeNodeMapper = WeakMapper>, TFilterData>, ITreeNode, TFilterData>>; + +class CompressibleAsyncDataTreeNodeWrapper implements ITreeNode, TFilterData> { + + get element(): ICompressedTreeNode { + return { + elements: this.node.element.elements.map(e => e.element), + incompressible: this.node.element.incompressible + }; + } + + get children(): ITreeNode, TFilterData>[] { return this.node.children.map(node => new CompressibleAsyncDataTreeNodeWrapper(node)); } + get depth(): number { return this.node.depth; } + get visibleChildrenCount(): number { return this.node.visibleChildrenCount; } + get visibleChildIndex(): number { return this.node.visibleChildIndex; } + get collapsible(): boolean { return this.node.collapsible; } + get collapsed(): boolean { return this.node.collapsed; } + get visible(): boolean { return this.node.visible; } + get filterData(): TFilterData | undefined { return this.node.filterData; } + + constructor(private node: ITreeNode>, TFilterData>) { } +} + +class CompressibleAsyncDataTreeRenderer implements ICompressibleTreeRenderer, TFilterData, IDataTreeListTemplateData> { + + readonly templateId: string; + private renderedNodes = new Map, IDataTreeListTemplateData>(); + private disposables: IDisposable[] = []; + + constructor( + protected renderer: ICompressibleTreeRenderer, + protected nodeMapper: AsyncDataTreeNodeMapper, + private compressibleNodeMapperProvider: () => CompressibleAsyncDataTreeNodeMapper, + readonly onDidChangeTwistieState: Event> + ) { + this.templateId = renderer.templateId; + } + + renderTemplate(container: HTMLElement): IDataTreeListTemplateData { + const templateData = this.renderer.renderTemplate(container); + return { templateData }; + } + + renderElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void { + this.renderer.renderElement(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height); + } + + renderCompressedElements(node: ITreeNode>, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void { + this.renderer.renderCompressedElements(this.compressibleNodeMapperProvider().map(node) as ITreeNode, TFilterData>, index, templateData.templateData, height); + } + + renderTwistie(element: IAsyncDataTreeNode, twistieElement: HTMLElement): boolean { + toggleClass(twistieElement, 'loading', element.slow); + return false; + } + + disposeElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void { + if (this.renderer.disposeElement) { + this.renderer.disposeElement(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height); + } + } + + disposeTemplate(templateData: IDataTreeListTemplateData): void { + this.renderer.disposeTemplate(templateData.templateData); + } + + dispose(): void { + this.renderedNodes.clear(); + this.disposables = dispose(this.disposables); + } +} + +export interface ITreeCompressionDelegate { + isIncompressible(element: T): boolean; +} + +export class CompressibleAsyncDataTree extends AsyncDataTree { + + protected readonly compressibleNodeMapper: CompressibleAsyncDataTreeNodeMapper = new WeakMapper(node => new CompressibleAsyncDataTreeNodeWrapper(node)); + + constructor( + user: string, + container: HTMLElement, + virtualDelegate: IListVirtualDelegate, + private compressionDelegate: ITreeCompressionDelegate, + renderers: ICompressibleTreeRenderer[], + dataSource: IAsyncDataSource, + options: IAsyncDataTreeOptions = {} + ) { + super(user, container, virtualDelegate, renderers, dataSource, options); + } + + protected createTree( + user: string, + container: HTMLElement, + delegate: IListVirtualDelegate, + renderers: ICompressibleTreeRenderer[], + options: IAsyncDataTreeOptions + ): ObjectTree, TFilterData> { + const objectTreeDelegate = new ComposedTreeDelegate>(delegate); + const objectTreeRenderers = renderers.map(r => new CompressibleAsyncDataTreeRenderer(r, this.nodeMapper, () => this.compressibleNodeMapper, this._onDidChangeNodeSlowState.event)); + const objectTreeOptions = asObjectTreeOptions(options) || {}; + + return new CompressibleObjectTree(user, container, objectTreeDelegate, objectTreeRenderers, objectTreeOptions); + } + + protected asTreeElement(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): ICompressedTreeElement> { + return { + incompressible: this.compressionDelegate.isIncompressible(node.element as T), + ...super.asTreeElement(node, viewStateContext) + }; + } +} diff --git a/src/vs/base/browser/ui/tree/compressedObjectTree.ts b/src/vs/base/browser/ui/tree/compressedObjectTree.ts deleted file mode 100644 index 9e5f2c9c9a..0000000000 --- a/src/vs/base/browser/ui/tree/compressedObjectTree.ts +++ /dev/null @@ -1,56 +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 { 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 59dd1a3eed..6bd87aa84b 100644 --- a/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts +++ b/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts @@ -6,19 +6,32 @@ 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 { ITreeModel, ITreeNode, ITreeElement, ICollapseStateChangeEvent, ITreeModelSpliceEvent, TreeError, TreeFilterResult, TreeVisibility, WeakMapper } from 'vs/base/browser/ui/tree/tree'; import { IObjectTreeModelOptions, ObjectTreeModel, IObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel'; +// Exported only for test reasons, do not use directly export interface ICompressedTreeElement extends ITreeElement { readonly children?: Iterator> | ICompressedTreeElement[]; readonly incompressible?: boolean; } +// Exported only for test reasons, do not use directly export interface ICompressedTreeNode { readonly elements: T[]; readonly incompressible: boolean; } +function noCompress(element: ICompressedTreeElement): ITreeElement> { + const elements = [element.element]; + const incompressible = element.incompressible || false; + + return { + element: { elements, incompressible }, + children: Iterator.map(Iterator.from(element.children), noCompress) + }; +} + +// Exported only for test reasons, do not use directly export function compress(element: ICompressedTreeElement): ITreeElement> { const elements = [element.element]; const incompressible = element.incompressible || false; @@ -49,7 +62,7 @@ export function compress(element: ICompressedTreeElement): ITreeElement(element: ITreeElement>, index = 0): ICompressedTreeElement { +function _decompress(element: ITreeElement>, index = 0): ICompressedTreeElement { let children: Iterator>; if (index < element.element.elements.length - 1) { @@ -65,11 +78,12 @@ export function _decompress(element: ITreeElement>, in return { element: element.element.elements[index], children }; } +// Exported only for test reasons, do not use directly export function decompress(element: ITreeElement>): ICompressedTreeElement { return _decompress(element, 0); } -export function splice(treeElement: ICompressedTreeElement, element: T, children: Iterator>): ICompressedTreeElement { +function splice(treeElement: ICompressedTreeElement, element: T, children: Iterator>): ICompressedTreeElement { if (treeElement.element === element) { return { element, children }; } @@ -80,9 +94,10 @@ export function splice(treeElement: ICompressedTreeElement, element: T, ch }; } -export interface ICompressedTreeModelOptions extends IObjectTreeModelOptions, TFilterData> { } +interface ICompressedObjectTreeModelOptions extends IObjectTreeModelOptions, TFilterData> { } -export class CompressedTreeModel, TFilterData extends NonNullable = void> implements ITreeModel | null, TFilterData, T | null> { +// Exported only for test reasons, do not use directly +export class CompressedObjectTreeModel, TFilterData extends NonNullable = void> implements ITreeModel | null, TFilterData, T | null> { readonly rootRef = null; @@ -92,35 +107,77 @@ export class CompressedTreeModel, TFilterData extends private model: ObjectTreeModel, TFilterData>; private nodes = new Map>(); + private enabled: boolean = true; get size(): number { return this.nodes.size; } - constructor(list: ISpliceable, TFilterData>>, options: ICompressedTreeModelOptions = {}) { - this.model = new ObjectTreeModel(list, options); + constructor( + private user: string, + list: ISpliceable, TFilterData>>, + options: ICompressedObjectTreeModelOptions = {} + ) { + this.model = new ObjectTreeModel(user, list, options); } setChildren( element: T | null, - children: ISequence> | undefined, - onDidCreateNode?: (node: ITreeNode, TFilterData>) => void, - onDidDeleteNode?: (node: ITreeNode, TFilterData>) => void - ): Iterator> { + children: ISequence> | undefined + ): void { + + if (element === null) { + const compressedChildren = Iterator.map(Iterator.from(children), this.enabled ? compress : noCompress); + this._setChildren(null, compressedChildren); + return; + } + + const compressedNode = this.nodes.get(element); + + if (!compressedNode) { + throw new Error('Unknown compressed tree node'); + } + + const node = this.model.getNode(compressedNode) as ITreeNode, TFilterData>; + const compressedParentNode = this.model.getParentNodeLocation(compressedNode); + const parent = this.model.getNode(compressedParentNode) as ITreeNode, TFilterData>; + + const decompressedElement = decompress(node); + const splicedElement = splice(decompressedElement, element, Iterator.from(children)); + const recompressedElement = (this.enabled ? compress : noCompress)(splicedElement); + + const parentChildren = parent.children + .map(child => child === node ? recompressedElement : child); + + this._setChildren(parent.element, parentChildren); + } + + isCompressionEnabled(): boolean { + return this.enabled; + } + + setCompressionEnabled(enabled: boolean): void { + if (enabled === this.enabled) { + return; + } + + this.enabled = enabled; + + const root = this.model.getNode(); + const rootChildren = Iterator.from((root.children as unknown) as ITreeNode>[]); // {{SQL CARBON EDIT}} strict-null-checks + const decompressedRootChildren = Iterator.map(rootChildren, decompress); + const recompressedRootChildren = Iterator.map(decompressedRootChildren, enabled ? compress : noCompress); + this._setChildren(null, recompressedRootChildren); + } + + private _setChildren( + node: ICompressedTreeNode | null, + children: ISequence>> | undefined + ): void { const insertedElements = new Set(); const _onDidCreateNode = (node: ITreeNode, TFilterData>) => { for (const element of node.element.elements) { insertedElements.add(element); this.nodes.set(element, node.element); } - - // if (this.identityProvider) { - // const id = this.identityProvider.getId(node.element).toString(); - // insertedElementIds.add(id); - // this.nodesByIdentity.set(id, node); - // } - - if (onDidCreateNode) { - onDidCreateNode(node); - } }; const _onDidDeleteNode = (node: ITreeNode, TFilterData>) => { @@ -129,40 +186,9 @@ export class CompressedTreeModel, TFilterData extends this.nodes.delete(element); } } - - // if (this.identityProvider) { - // const id = this.identityProvider.getId(node.element).toString(); - // if (!insertedElementIds.has(id)) { - // this.nodesByIdentity.delete(id); - // } - // } - - if (onDidDeleteNode) { - onDidDeleteNode(node); - } }; - if (element === null) { - const compressedChildren = Iterator.map(Iterator.from(children), compress); - const result = this.model.setChildren(null, compressedChildren, _onDidCreateNode, _onDidDeleteNode); - return Iterator.map(result, decompress); - } - - const compressedNode = this.nodes.get(element); - const node = this.model.getNode(compressedNode) as ITreeNode, TFilterData>; - const parent = node.parent!; - - const decompressedElement = decompress(node); - const splicedElement = splice(decompressedElement, element, Iterator.from(children)); - const recompressedElement = compress(splicedElement); - - const parentChildren = parent.children - .map(child => child === node ? recompressedElement : child); - - this.model.setChildren(parent.element, parentChildren, _onDidCreateNode, _onDidDeleteNode); - - // TODO - return Iterator.empty(); + this.model.setChildren(node, children, _onDidCreateNode, _onDidDeleteNode); } getListIndex(location: T | null): number { @@ -207,11 +233,6 @@ export class CompressedTreeModel, TFilterData extends return parentNode.elements[parentNode.elements.length - 1]; } - getParentElement(location: T | null): ICompressedTreeNode | null { - const compressedNode = this.getCompressedNode(location); - return this.model.getParentElement(compressedNode); - } - getFirstElementChild(location: T | null): ICompressedTreeNode | null | undefined { const compressedNode = this.getCompressedNode(location); return this.model.getFirstElementChild(compressedNode); @@ -227,6 +248,11 @@ export class CompressedTreeModel, TFilterData extends return this.model.isCollapsible(compressedNode); } + setCollapsible(location: T | null, collapsible?: boolean): boolean { + const compressedNode = this.getCompressedNode(location); + return this.model.setCollapsible(compressedNode, collapsible); + } + isCollapsed(location: T | null): boolean { const compressedNode = this.getCompressedNode(location); return this.model.isCollapsed(compressedNode); @@ -256,7 +282,7 @@ export class CompressedTreeModel, TFilterData extends this.model.resort(compressedNode, recursive); } - private getCompressedNode(element: T | null): ICompressedTreeNode | null { + getCompressedNode(element: T | null): ICompressedTreeNode | null { if (element === null) { return null; } @@ -264,78 +290,120 @@ export class CompressedTreeModel, TFilterData extends const node = this.nodes.get(element); if (!node) { - throw new Error(`Tree element not found: ${element}`); + throw new TreeError(this.user, `Tree element not found: ${element}`); } return node; } } +// Compressible Object Tree + export type ElementMapper = (elements: T[]) => T; export const DefaultElementMapper: ElementMapper = elements => elements[elements.length - 1]; -export type NodeMapper = (node: ITreeNode | null, TFilterData>) => ITreeNode; +export type CompressedNodeUnwrapper = (node: ICompressedTreeNode) => T; +type CompressedNodeWeakMapper = WeakMapper | null, TFilterData>, ITreeNode>; -function mapNode(elementMapper: ElementMapper, node: ITreeNode | null, TFilterData>): ITreeNode { +class CompressedTreeNodeWrapper implements ITreeNode { + + get element(): T | null { return this.node.element === null ? null : this.unwrapper(this.node.element); } + get children(): ITreeNode[] { return this.node.children.map(node => new CompressedTreeNodeWrapper(this.unwrapper, node)); } + get depth(): number { return this.node.depth; } + get visibleChildrenCount(): number { return this.node.visibleChildrenCount; } + get visibleChildIndex(): number { return this.node.visibleChildIndex; } + get collapsible(): boolean { return this.node.collapsible; } + get collapsed(): boolean { return this.node.collapsed; } + get visible(): boolean { return this.node.visible; } + get filterData(): TFilterData | undefined { return this.node.filterData; } + + constructor( + private unwrapper: CompressedNodeUnwrapper, + private node: ITreeNode | null, TFilterData> + ) { } +} + +function mapList(nodeMapper: CompressedNodeWeakMapper, list: ISpliceable>): ISpliceable, TFilterData>> { return { - ...node, - element: node.element === null ? null : elementMapper(node.element.elements), - children: node.children.map(child => mapNode(elementMapper, child)), - parent: typeof node.parent === 'undefined' ? node.parent : mapNode(elementMapper, node.parent) + splice(start: number, deleteCount: number, toInsert: ITreeNode, TFilterData>[]): void { + list.splice(start, deleteCount, toInsert.map(node => nodeMapper.map(node)) as ITreeNode[]); + } }; } -function createNodeMapper(elementMapper: ElementMapper): NodeMapper { - return node => mapNode(elementMapper, node); +function mapOptions(compressedNodeUnwrapper: CompressedNodeUnwrapper, options: ICompressibleObjectTreeModelOptions): ICompressedObjectTreeModelOptions { + return { + ...options, + sorter: options.sorter && { + compare(node: ICompressedTreeNode, otherNode: ICompressedTreeNode): number { + return options.sorter!.compare(compressedNodeUnwrapper(node), compressedNodeUnwrapper(otherNode)); + } + }, + identityProvider: options.identityProvider && { + getId(node: ICompressedTreeNode): { toString(): string; } { + return options.identityProvider!.getId(compressedNodeUnwrapper(node)); + } + }, + filter: options.filter && { + filter(node: ICompressedTreeNode, parentVisibility: TreeVisibility): TreeFilterResult { + return options.filter!.filter(compressedNodeUnwrapper(node), parentVisibility); + } + } + }; } -export interface ICompressedObjectTreeModelOptions extends ICompressedTreeModelOptions { +export interface ICompressibleObjectTreeModelOptions extends IObjectTreeModelOptions { readonly elementMapper?: ElementMapper; } -export class CompressedObjectTreeModel, TFilterData extends NonNullable = void> implements IObjectTreeModel { +export class CompressibleObjectTreeModel, TFilterData extends NonNullable = void> implements IObjectTreeModel { readonly rootRef = null; get onDidSplice(): Event> { return Event.map(this.model.onDidSplice, ({ insertedNodes, deletedNodes }) => ({ - insertedNodes: insertedNodes.map(this.mapNode), - deletedNodes: deletedNodes.map(this.mapNode), + insertedNodes: insertedNodes.map(node => this.nodeMapper.map(node)), + deletedNodes: deletedNodes.map(node => this.nodeMapper.map(node)), })); } get onDidChangeCollapseState(): Event> { return Event.map(this.model.onDidChangeCollapseState, ({ node, deep }) => ({ - node: this.mapNode(node), + node: this.nodeMapper.map(node), deep })); } get onDidChangeRenderNodeCount(): Event> { - return Event.map(this.model.onDidChangeRenderNodeCount, this.mapNode); + return Event.map(this.model.onDidChangeRenderNodeCount, node => this.nodeMapper.map(node)); } - private mapElement: ElementMapper; - private mapNode: NodeMapper; - private model: CompressedTreeModel; + private elementMapper: ElementMapper; + private nodeMapper: CompressedNodeWeakMapper; + private model: CompressedObjectTreeModel; constructor( - list: ISpliceable, TFilterData>>, - options: ICompressedObjectTreeModelOptions = {} + user: string, + list: ISpliceable>, + options: ICompressibleObjectTreeModelOptions = {} ) { - this.mapElement = options.elementMapper || DefaultElementMapper; - this.mapNode = createNodeMapper(this.mapElement); - this.model = new CompressedTreeModel(list, options); + this.elementMapper = options.elementMapper || DefaultElementMapper; + const compressedNodeUnwrapper: CompressedNodeUnwrapper = node => this.elementMapper(node.elements); + this.nodeMapper = new WeakMapper(node => new CompressedTreeNodeWrapper(compressedNodeUnwrapper, node)); + + this.model = new CompressedObjectTreeModel(user, mapList(this.nodeMapper, list), mapOptions(compressedNodeUnwrapper, options)); } - setChildren( - element: T | null, - children: ISequence> | undefined - ): Iterator> { + setChildren(element: T | null, children?: ISequence>): void { this.model.setChildren(element, children); + } - // TODO - return Iterator.empty(); + isCompressionEnabled(): boolean { + return this.model.isCompressionEnabled(); + } + + setCompressionEnabled(enabled: boolean): void { + this.model.setCompressionEnabled(enabled); } getListIndex(location: T | null): number { @@ -347,7 +415,7 @@ export class CompressedObjectTreeModel, TFilterData e } getNode(location?: T | null | undefined): ITreeNode { - return this.mapNode(this.model.getNode(location)); + return this.nodeMapper.map(this.model.getNode(location)); } getNodeLocation(node: ITreeNode): T | null { @@ -358,16 +426,6 @@ export class CompressedObjectTreeModel, TFilterData e return this.model.getParentNodeLocation(location); } - getParentElement(location: T | null): T | null { - const result = this.model.getParentElement(location); - - if (result === null) { - return null; // {{SQL CARBON EDIT}} strict-null-check - } - - return this.mapElement(result.elements); - } - getFirstElementChild(location: T | null): T | null | undefined { const result = this.model.getFirstElementChild(location); @@ -375,7 +433,7 @@ export class CompressedObjectTreeModel, TFilterData e return null; // {{SQL CARBON EDIT}} strict-null-check } - return this.mapElement(result.elements); + return this.elementMapper(result.elements); } getLastElementAncestor(location?: T | null | undefined): T | null | undefined { @@ -385,13 +443,17 @@ export class CompressedObjectTreeModel, TFilterData e return null; // {{SQL CARBON EDIT}} strict-null-check } - return this.mapElement(result.elements); + return this.elementMapper(result.elements); } isCollapsible(location: T | null): boolean { return this.model.isCollapsible(location); } + setCollapsible(location: T | null, collapsed?: boolean): boolean { + return this.model.setCollapsible(location, collapsed); + } + isCollapsed(location: T | null): boolean { return this.model.isCollapsed(location); } @@ -415,4 +477,8 @@ export class CompressedObjectTreeModel, TFilterData e resort(element: T | null = null, recursive = true): void { return this.model.resort(element, recursive); } -} \ No newline at end of file + + getCompressedTreeNode(element: T): ITreeNode, TFilterData> { + return this.model.getNode(element) as ITreeNode, TFilterData>; + } +} diff --git a/src/vs/base/browser/ui/tree/dataTree.ts b/src/vs/base/browser/ui/tree/dataTree.ts index ffded10a45..742607faea 100644 --- a/src/vs/base/browser/ui/tree/dataTree.ts +++ b/src/vs/base/browser/ui/tree/dataTree.ts @@ -5,7 +5,7 @@ import { AbstractTree, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree'; import { ISpliceable } from 'vs/base/common/sequence'; -import { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter, IDataSource } from 'vs/base/browser/ui/tree/tree'; +import { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter, IDataSource, TreeError } from 'vs/base/browser/ui/tree/tree'; import { ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel'; import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list'; import { Iterator } from 'vs/base/common/iterator'; @@ -30,13 +30,14 @@ export class DataTree extends AbstractTree>(); constructor( + private user: string, container: HTMLElement, delegate: IListVirtualDelegate, renderers: ITreeRenderer[], private dataSource: IDataSource, options: IDataTreeOptions = {} ) { - super(container, delegate, renderers, options); + super(user, container, delegate, renderers, options); this.identityProvider = options.identityProvider; } @@ -48,7 +49,7 @@ export class DataTree extends AbstractTree extends AbstractTree boolean | undefined) | undefined; @@ -169,15 +170,15 @@ export class DataTree extends AbstractTree>, options: IDataTreeOptions): ITreeModel { - return new ObjectTreeModel(view, options); + protected createModel(user: string, view: ISpliceable>, options: IDataTreeOptions): ITreeModel { + return new ObjectTreeModel(user, view, options); } // view state getViewState(): IDataTreeViewState { if (!this.identityProvider) { - throw new Error('Can\'t get tree view state without an identity provider'); + throw new TreeError(this.user, 'Can\'t get tree view state without an identity provider'); } const getId = (element: T) => this.identityProvider!.getId(element).toString(); diff --git a/src/vs/base/browser/ui/tree/indexTree.ts b/src/vs/base/browser/ui/tree/indexTree.ts index b709f66b29..4df112db6b 100644 --- a/src/vs/base/browser/ui/tree/indexTree.ts +++ b/src/vs/base/browser/ui/tree/indexTree.ts @@ -18,17 +18,18 @@ export class IndexTree extends AbstractTree; constructor( + user: string, container: HTMLElement, delegate: IListVirtualDelegate, renderers: ITreeRenderer[], private rootElement: T, options: IIndexTreeOptions = {} ) { - super(container, delegate, renderers, options); + super(user, container, delegate, renderers, options); } - splice(location: number[], deleteCount: number, toInsert: ISequence> = Iterator.empty()): Iterator> { - return this.model.splice(location, deleteCount, toInsert); + splice(location: number[], deleteCount: number, toInsert: ISequence> = Iterator.empty()): void { + this.model.splice(location, deleteCount, toInsert); } rerender(location?: number[]): void { @@ -40,7 +41,7 @@ export class IndexTree extends AbstractTree>, options: IIndexTreeOptions): ITreeModel { - return new IndexTreeModel(view, this.rootElement, options); + protected createModel(user: string, view: ISpliceable>, options: IIndexTreeOptions): ITreeModel { + return new IndexTreeModel(user, view, this.rootElement, options); } } diff --git a/src/vs/base/browser/ui/tree/indexTreeModel.ts b/src/vs/base/browser/ui/tree/indexTreeModel.ts index 19954afdf5..6b1966761c 100644 --- a/src/vs/base/browser/ui/tree/indexTreeModel.ts +++ b/src/vs/base/browser/ui/tree/indexTreeModel.ts @@ -3,15 +3,16 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ICollapseStateChangeEvent, ITreeElement, ITreeFilter, ITreeFilterDataResult, ITreeModel, ITreeNode, TreeVisibility, ITreeModelSpliceEvent } from 'vs/base/browser/ui/tree/tree'; +import { ICollapseStateChangeEvent, ITreeElement, ITreeFilter, ITreeFilterDataResult, ITreeModel, ITreeNode, TreeVisibility, ITreeModelSpliceEvent, TreeError } from 'vs/base/browser/ui/tree/tree'; import { tail2 } from 'vs/base/common/arrays'; import { Emitter, Event, EventBufferer } from 'vs/base/common/event'; import { ISequence, Iterator } from 'vs/base/common/iterator'; import { ISpliceable } from 'vs/base/common/sequence'; -interface IMutableTreeNode extends ITreeNode { - readonly parent: IMutableTreeNode | undefined; - readonly children: IMutableTreeNode[]; +// Exported for tests +export interface IIndexTreeNode extends ITreeNode { + readonly parent: IIndexTreeNode | undefined; + readonly children: IIndexTreeNode[]; visibleChildrenCount: number; visibleChildIndex: number; collapsible: boolean; @@ -33,24 +34,32 @@ export function getVisibleState(visibility: boolean | TreeVisibility): TreeVisib } } -function treeNodeToElement(node: IMutableTreeNode): ITreeElement { - const { element, collapsed } = node; - const children = Iterator.map(Iterator.fromArray(node.children), treeNodeToElement); - - return { element, children, collapsed }; -} - export interface IIndexTreeModelOptions { readonly collapseByDefault?: boolean; // defaults to false readonly filter?: ITreeFilter; readonly autoExpandSingleChildren?: boolean; } +interface CollapsibleStateUpdate { + readonly collapsible: boolean; +} + +interface CollapsedStateUpdate { + readonly collapsed: boolean; + readonly recursive: boolean; +} + +type CollapseStateUpdate = CollapsibleStateUpdate | CollapsedStateUpdate; + +function isCollapsibleStateUpdate(update: CollapseStateUpdate): update is CollapsibleStateUpdate { + return typeof (update as any).collapsible === 'boolean'; +} + export class IndexTreeModel, TFilterData = void> implements ITreeModel { readonly rootRef = []; - private root: IMutableTreeNode; + private root: IIndexTreeNode; private eventBufferer = new EventBufferer(); private _onDidChangeCollapseState = new Emitter>(); @@ -66,7 +75,12 @@ export class IndexTreeModel, TFilterData = voi private _onDidSplice = new Emitter>(); readonly onDidSplice = this._onDidSplice.event; - constructor(private list: ISpliceable>, rootElement: T, options: IIndexTreeModelOptions = {}) { + constructor( + private user: string, + private list: ISpliceable>, + rootElement: T, + options: IIndexTreeModelOptions = {} + ) { this.collapseByDefault = typeof options.collapseByDefault === 'undefined' ? false : options.collapseByDefault; this.filter = options.filter; this.autoExpandSingleChildren = typeof options.autoExpandSingleChildren === 'undefined' ? false : options.autoExpandSingleChildren; @@ -92,9 +106,9 @@ export class IndexTreeModel, TFilterData = voi toInsert?: ISequence>, onDidCreateNode?: (node: ITreeNode) => void, onDidDeleteNode?: (node: ITreeNode) => void - ): Iterator> { + ): void { if (location.length === 0) { - throw new Error('Invalid tree location'); + throw new TreeError(this.user, 'Invalid tree location'); } const { parentNode, listIndex, revealed, visible } = this.getParentNodeWithListIndex(location); @@ -116,7 +130,7 @@ export class IndexTreeModel, TFilterData = voi } } - const nodesToInsert: IMutableTreeNode[] = []; + const nodesToInsert: IIndexTreeNode[] = []; let insertedVisibleChildrenCount = 0; let renderNodeCount = 0; @@ -170,14 +184,12 @@ export class IndexTreeModel, TFilterData = voi deletedNodes.forEach(visit); } - const result = Iterator.map(Iterator.fromArray(deletedNodes), treeNodeToElement); this._onDidSplice.fire({ insertedNodes: nodesToInsert, deletedNodes }); - return result; } rerender(location: number[]): void { if (location.length === 0) { - throw new Error('Invalid tree location'); + throw new TreeError(this.user, 'Invalid tree location'); } const { node, listIndex, revealed } = this.getTreeNodeWithListIndex(location); @@ -200,6 +212,17 @@ export class IndexTreeModel, TFilterData = voi return this.getTreeNode(location).collapsible; } + setCollapsible(location: number[], collapsible?: boolean): boolean { + const node = this.getTreeNode(location); + + if (typeof collapsible === 'undefined') { + collapsible = !node.collapsible; + } + + const update: CollapsibleStateUpdate = { collapsible }; + return this.eventBufferer.bufferEvents(() => this._setCollapseState(location, update)); + } + isCollapsed(location: number[]): boolean { return this.getTreeNode(location).collapsed; } @@ -211,15 +234,16 @@ export class IndexTreeModel, TFilterData = voi collapsed = !node.collapsed; } - return this.eventBufferer.bufferEvents(() => this._setCollapsed(location, collapsed!, recursive)); + const update: CollapsedStateUpdate = { collapsed, recursive: recursive || false }; + return this.eventBufferer.bufferEvents(() => this._setCollapseState(location, update)); } - private _setCollapsed(location: number[], collapsed: boolean, recursive?: boolean): boolean { + private _setCollapseState(location: number[], update: CollapseStateUpdate): boolean { const { node, listIndex, revealed } = this.getTreeNodeWithListIndex(location); - const result = this._setListNodeCollapsed(node, listIndex, revealed, collapsed!, recursive || false); + const result = this._setListNodeCollapseState(node, listIndex, revealed, update); - if (node !== this.root && this.autoExpandSingleChildren && !collapsed! && !recursive) { + if (node !== this.root && this.autoExpandSingleChildren && result && !isCollapsibleStateUpdate(update) && node.collapsible && !node.collapsed && !update.recursive) { let onlyVisibleChildIndex = -1; for (let i = 0; i < node.children.length; i++) { @@ -236,17 +260,17 @@ export class IndexTreeModel, TFilterData = voi } if (onlyVisibleChildIndex > -1) { - this._setCollapsed([...location, onlyVisibleChildIndex], false, false); + this._setCollapseState([...location, onlyVisibleChildIndex], update); } } return result; } - private _setListNodeCollapsed(node: IMutableTreeNode, listIndex: number, revealed: boolean, collapsed: boolean, recursive: boolean): boolean { - const result = this._setNodeCollapsed(node, collapsed, recursive, false); + private _setListNodeCollapseState(node: IIndexTreeNode, listIndex: number, revealed: boolean, update: CollapseStateUpdate): boolean { + const result = this._setNodeCollapseState(node, update, false); - if (!revealed || !node.visible) { + if (!revealed || !node.visible || !result) { return result; } @@ -258,20 +282,28 @@ export class IndexTreeModel, TFilterData = voi return result; } - private _setNodeCollapsed(node: IMutableTreeNode, collapsed: boolean, recursive: boolean, deep: boolean): boolean { - let result = node.collapsible && node.collapsed !== collapsed; + private _setNodeCollapseState(node: IIndexTreeNode, update: CollapseStateUpdate, deep: boolean): boolean { + let result: boolean; - if (node.collapsible) { - node.collapsed = collapsed; + if (node === this.root) { + result = false; + } else { + if (isCollapsibleStateUpdate(update)) { + result = node.collapsible !== update.collapsible; + node.collapsible = update.collapsible; + } else { + result = node.collapsed !== update.collapsed; + node.collapsed = update.collapsed; + } if (result) { this._onDidChangeCollapseState.fire({ node, deep }); } } - if (recursive) { + if (!isCollapsibleStateUpdate(update) && update.recursive) { for (const child of node.children) { - result = this._setNodeCollapsed(child, collapsed, true, true) || result; + result = this._setNodeCollapseState(child, update, true) || result; } } @@ -287,7 +319,7 @@ export class IndexTreeModel, TFilterData = voi location = location.slice(0, location.length - 1); if (node.collapsed) { - this._setCollapsed(location, false); + this._setCollapseState(location, { collapsed: false, recursive: false }); } } }); @@ -301,13 +333,13 @@ export class IndexTreeModel, TFilterData = voi private createTreeNode( treeElement: ITreeElement, - parent: IMutableTreeNode, + parent: IIndexTreeNode, parentVisibility: TreeVisibility, revealed: boolean, treeListElements: ITreeNode[], onDidCreateNode?: (node: ITreeNode) => void - ): IMutableTreeNode { - const node: IMutableTreeNode = { + ): IIndexTreeNode { + const node: IIndexTreeNode = { parent, element: treeElement.element, children: [], @@ -364,7 +396,7 @@ export class IndexTreeModel, TFilterData = voi return node; } - private updateNodeAfterCollapseChange(node: IMutableTreeNode): ITreeNode[] { + private updateNodeAfterCollapseChange(node: IIndexTreeNode): ITreeNode[] { const previousRenderNodeCount = node.renderNodeCount; const result: ITreeNode[] = []; @@ -374,7 +406,7 @@ export class IndexTreeModel, TFilterData = voi return result; } - private _updateNodeAfterCollapseChange(node: IMutableTreeNode, result: ITreeNode[]): number { + private _updateNodeAfterCollapseChange(node: IIndexTreeNode, result: ITreeNode[]): number { if (node.visible === false) { return 0; } @@ -392,7 +424,7 @@ export class IndexTreeModel, TFilterData = voi return node.renderNodeCount; } - private updateNodeAfterFilterChange(node: IMutableTreeNode): ITreeNode[] { + private updateNodeAfterFilterChange(node: IIndexTreeNode): ITreeNode[] { const previousRenderNodeCount = node.renderNodeCount; const result: ITreeNode[] = []; @@ -402,7 +434,7 @@ export class IndexTreeModel, TFilterData = voi return result; } - private _updateNodeAfterFilterChange(node: IMutableTreeNode, parentVisibility: TreeVisibility, result: ITreeNode[], revealed = true): boolean { + private _updateNodeAfterFilterChange(node: IIndexTreeNode, parentVisibility: TreeVisibility, result: ITreeNode[], revealed = true): boolean { let visibility: TreeVisibility; if (node !== this.root) { @@ -456,7 +488,7 @@ export class IndexTreeModel, TFilterData = voi return node.visible; } - private _updateAncestorsRenderNodeCount(node: IMutableTreeNode | undefined, diff: number): void { + private _updateAncestorsRenderNodeCount(node: IIndexTreeNode | undefined, diff: number): void { if (diff === 0) { return; } @@ -468,7 +500,7 @@ export class IndexTreeModel, TFilterData = voi } } - private _filterNode(node: IMutableTreeNode, parentVisibility: TreeVisibility): TreeVisibility { + private _filterNode(node: IIndexTreeNode, parentVisibility: TreeVisibility): TreeVisibility { const result = this.filter ? this.filter.filter(node.element, parentVisibility) : TreeVisibility.Visible; if (typeof result === 'boolean') { @@ -484,7 +516,7 @@ export class IndexTreeModel, TFilterData = voi } // cheap - private getTreeNode(location: number[], node: IMutableTreeNode = this.root): IMutableTreeNode { + private getTreeNode(location: number[], node: IIndexTreeNode = this.root): IIndexTreeNode { if (!location || location.length === 0) { return node; } @@ -492,14 +524,14 @@ export class IndexTreeModel, TFilterData = voi const [index, ...rest] = location; if (index < 0 || index > node.children.length) { - throw new Error('Invalid tree location'); + throw new TreeError(this.user, 'Invalid tree location'); } return this.getTreeNode(rest, node.children[index]); } // expensive - private getTreeNodeWithListIndex(location: number[]): { node: IMutableTreeNode, listIndex: number, revealed: boolean, visible: boolean } { + private getTreeNodeWithListIndex(location: number[]): { node: IIndexTreeNode, listIndex: number, revealed: boolean, visible: boolean } { if (location.length === 0) { return { node: this.root, listIndex: -1, revealed: true, visible: false }; } @@ -508,7 +540,7 @@ export class IndexTreeModel, TFilterData = voi const index = location[location.length - 1]; if (index < 0 || index > parentNode.children.length) { - throw new Error('Invalid tree location'); + throw new TreeError(this.user, 'Invalid tree location'); } const node = parentNode.children[index]; @@ -516,11 +548,11 @@ export class IndexTreeModel, TFilterData = voi return { node, listIndex, revealed, visible: visible && node.visible }; } - private getParentNodeWithListIndex(location: number[], node: IMutableTreeNode = this.root, listIndex: number = 0, revealed = true, visible = true): { parentNode: IMutableTreeNode; listIndex: number; revealed: boolean; visible: boolean; } { + private getParentNodeWithListIndex(location: number[], node: IIndexTreeNode = this.root, listIndex: number = 0, revealed = true, visible = true): { parentNode: IIndexTreeNode; listIndex: number; revealed: boolean; visible: boolean; } { const [index, ...rest] = location; if (index < 0 || index > node.children.length) { - throw new Error('Invalid tree location'); + throw new TreeError(this.user, 'Invalid tree location'); } // TODO@joao perf! @@ -545,27 +577,24 @@ export class IndexTreeModel, TFilterData = voi // TODO@joao perf! getNodeLocation(node: ITreeNode): number[] { const location: number[] = []; + let indexTreeNode = node as IIndexTreeNode; // typing woes - while (node.parent) { - location.push(node.parent.children.indexOf(node)); - node = node.parent; + while (indexTreeNode.parent) { + location.push(indexTreeNode.parent.children.indexOf(indexTreeNode)); + indexTreeNode = indexTreeNode.parent; } return location.reverse(); } - getParentNodeLocation(location: number[]): number[] { - if (location.length <= 1) { + getParentNodeLocation(location: number[]): number[] | undefined { + if (location.length === 0) { + return undefined; + } else if (location.length === 1) { return []; + } else { + return tail2(location)[0]; } - - return tail2(location)[0]; - } - - getParentElement(location: number[]): T { - const parentLocation = this.getParentNodeLocation(location); - const node = this.getTreeNode(parentLocation); - return node.element; } getFirstElementChild(location: number[]): T | undefined { diff --git a/src/vs/base/browser/ui/tree/objectTree.ts b/src/vs/base/browser/ui/tree/objectTree.ts index b5b40425dc..d8c2195e81 100644 --- a/src/vs/base/browser/ui/tree/objectTree.ts +++ b/src/vs/base/browser/ui/tree/objectTree.ts @@ -3,13 +3,14 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Iterator, ISequence } from 'vs/base/common/iterator'; +import { 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, IObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel'; import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { Event } from 'vs/base/common/event'; +import { CompressibleObjectTreeModel, ElementMapper, ICompressedTreeNode, ICompressedTreeElement } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; export interface IObjectTreeOptions extends IAbstractTreeOptions { sorter?: ITreeSorter; @@ -22,19 +23,17 @@ export class ObjectTree, TFilterData = void> extends get onDidChangeCollapseState(): Event> { return this.model.onDidChangeCollapseState; } constructor( + user: string, container: HTMLElement, delegate: IListVirtualDelegate, renderers: ITreeRenderer[], options: IObjectTreeOptions = {} ) { - super(container, delegate, renderers, options); + super(user, container, delegate, renderers, options); } - setChildren( - element: T | null, - children?: ISequence> - ): Iterator> { - return this.model.setChildren(element, children); + setChildren(element: T | null, children?: ISequence>): void { + this.model.setChildren(element, children); } rerender(element?: T): void { @@ -50,7 +49,117 @@ export class ObjectTree, TFilterData = void> extends this.model.resort(element, recursive); } - protected createModel(view: ISpliceable>, options: IObjectTreeOptions): ITreeModel { - return new ObjectTreeModel(view, options); + protected createModel(user: string, view: ISpliceable>, options: IObjectTreeOptions): ITreeModel { + return new ObjectTreeModel(user, view, options); + } +} + +interface ICompressedTreeNodeProvider { + getCompressedTreeNode(element: T): ITreeNode, TFilterData>; +} + +export interface ICompressibleObjectTreeOptions extends IObjectTreeOptions { + readonly elementMapper?: ElementMapper; +} + +export interface ICompressibleTreeRenderer extends ITreeRenderer { + renderCompressedElements(node: ITreeNode, TFilterData>, index: number, templateData: TTemplateData, height: number | undefined): void; + disposeCompressedElements?(node: ITreeNode, TFilterData>, index: number, templateData: TTemplateData, height: number | undefined): void; +} + +interface CompressibleTemplateData { + compressedTreeNode: ITreeNode, TFilterData> | undefined; + readonly data: TTemplateData; +} + +class CompressibleRenderer implements ITreeRenderer> { + + readonly templateId: string; + readonly onDidChangeTwistieState: Event | undefined; + + compressedTreeNodeProvider: ICompressedTreeNodeProvider; + + constructor(private renderer: ICompressibleTreeRenderer) { + this.templateId = renderer.templateId; + + if (renderer.onDidChangeTwistieState) { + this.onDidChangeTwistieState = renderer.onDidChangeTwistieState; + } + } + + renderTemplate(container: HTMLElement): CompressibleTemplateData { + const data = this.renderer.renderTemplate(container); + return { compressedTreeNode: undefined, data }; + } + + renderElement(node: ITreeNode, index: number, templateData: CompressibleTemplateData, height: number | undefined): void { + const compressedTreeNode = this.compressedTreeNodeProvider.getCompressedTreeNode(node.element); + + if (compressedTreeNode.element.elements.length === 1) { + templateData.compressedTreeNode = undefined; + this.renderer.renderElement(node, index, templateData.data, height); + } else { + templateData.compressedTreeNode = compressedTreeNode; + this.renderer.renderCompressedElements(compressedTreeNode, index, templateData.data, height); + } + } + + disposeElement(node: ITreeNode, index: number, templateData: CompressibleTemplateData, height: number | undefined): void { + if (templateData.compressedTreeNode) { + if (this.renderer.disposeCompressedElements) { + this.renderer.disposeCompressedElements(templateData.compressedTreeNode, index, templateData.data, height); + } + } else { + if (this.renderer.disposeElement) { + this.renderer.disposeElement(node, index, templateData.data, height); + } + } + } + + disposeTemplate(templateData: CompressibleTemplateData): void { + this.renderer.disposeTemplate(templateData.data); + } + + renderTwistie?(element: T, twistieElement: HTMLElement): void { + if (this.renderer.renderTwistie) { + this.renderer.renderTwistie(element, twistieElement); + } + } +} + +export class CompressibleObjectTree, TFilterData = void> extends ObjectTree { + + protected model: CompressibleObjectTreeModel; + + constructor( + user: string, + container: HTMLElement, + delegate: IListVirtualDelegate, + renderers: ICompressibleTreeRenderer[], + options: IObjectTreeOptions = {} + ) { + const compressibleRenderers = renderers.map(r => new CompressibleRenderer(r)); + super(user, container, delegate, compressibleRenderers, options); + compressibleRenderers.forEach(r => r.compressedTreeNodeProvider = this); + } + + setChildren(element: T | null, children?: ISequence>): void { + this.model.setChildren(element, children); + } + + protected createModel(user: string, view: ISpliceable>, options: ICompressibleObjectTreeOptions): ITreeModel { + return new CompressibleObjectTreeModel(user, view, options); + } + + isCompressionEnabled(): boolean { + return this.model.isCompressionEnabled(); + } + + setCompressionEnabled(enabled: boolean): void { + this.model.setCompressionEnabled(enabled); + } + + getCompressedTreeNode(element: T): ITreeNode, TFilterData> { + return this.model.getCompressedTreeNode(element)!; } } diff --git a/src/vs/base/browser/ui/tree/objectTreeModel.ts b/src/vs/base/browser/ui/tree/objectTreeModel.ts index 083ff5d2fd..e21362349c 100644 --- a/src/vs/base/browser/ui/tree/objectTreeModel.ts +++ b/src/vs/base/browser/ui/tree/objectTreeModel.ts @@ -7,13 +7,13 @@ import { ISpliceable } from 'vs/base/common/sequence'; import { Iterator, ISequence, getSequenceIterator } from 'vs/base/common/iterator'; import { IndexTreeModel, IIndexTreeModelOptions } from 'vs/base/browser/ui/tree/indexTreeModel'; import { Event } from 'vs/base/common/event'; -import { ITreeModel, ITreeNode, ITreeElement, ITreeSorter, ICollapseStateChangeEvent, ITreeModelSpliceEvent } from 'vs/base/browser/ui/tree/tree'; +import { ITreeModel, ITreeNode, ITreeElement, ITreeSorter, ICollapseStateChangeEvent, ITreeModelSpliceEvent, TreeError } 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>; + setChildren(element: T | null, children: ISequence> | undefined): void; resort(element?: T | null, recursive?: boolean): void; } @@ -38,8 +38,12 @@ export class ObjectTreeModel, TFilterData extends Non get size(): number { return this.nodes.size; } - constructor(list: ISpliceable>, options: IObjectTreeModelOptions = {}) { - this.model = new IndexTreeModel(list, null, options); + constructor( + private user: string, + list: ISpliceable>, + options: IObjectTreeModelOptions = {} + ) { + this.model = new IndexTreeModel(user, list, null, options); this.onDidSplice = this.model.onDidSplice; this.onDidChangeCollapseState = this.model.onDidChangeCollapseState as Event>; this.onDidChangeRenderNodeCount = this.model.onDidChangeRenderNodeCount as Event>; @@ -60,9 +64,9 @@ export class ObjectTreeModel, TFilterData extends Non children: ISequence> | undefined, onDidCreateNode?: ITreeNodeCallback, onDidDeleteNode?: ITreeNodeCallback - ): Iterator> { + ): void { const location = this.getElementLocation(element); - return this._setChildren(location, this.preserveCollapseState(children), onDidCreateNode, onDidDeleteNode); + this._setChildren(location, this.preserveCollapseState(children), onDidCreateNode, onDidDeleteNode); } private _setChildren( @@ -70,7 +74,7 @@ export class ObjectTreeModel, TFilterData extends Non children: ISequence> | undefined, onDidCreateNode?: ITreeNodeCallback, onDidDeleteNode?: ITreeNodeCallback - ): Iterator> { + ): void { const insertedElements = new Set(); const insertedElementIds = new Set(); @@ -106,15 +110,13 @@ export class ObjectTreeModel, TFilterData extends Non } }; - const result = this.model.splice( + this.model.splice( [...location, 0], Number.MAX_VALUE, children, _onDidCreateNode, _onDidDeleteNode ); - - return result as Iterator>; } private preserveCollapseState(elements: ISequence> | undefined): ISequence> { @@ -182,11 +184,6 @@ export class ObjectTreeModel, TFilterData extends Non })); } - getParentElement(ref: T | null = null): T | null { - const location = this.getElementLocation(ref); - return this.model.getParentElement(location); - } - getFirstElementChild(ref: T | null = null): T | null | undefined { const location = this.getElementLocation(ref); return this.model.getFirstElementChild(location); @@ -212,6 +209,11 @@ export class ObjectTreeModel, TFilterData extends Non return this.model.isCollapsible(location); } + setCollapsible(element: T | null, collapsible?: boolean): boolean { + const location = this.getElementLocation(element); + return this.model.setCollapsible(location, collapsible); + } + isCollapsed(element: T | null): boolean { const location = this.getElementLocation(element); return this.model.isCollapsed(location); @@ -239,7 +241,7 @@ export class ObjectTreeModel, TFilterData extends Non const node = this.nodes.get(element); if (!node) { - throw new Error(`Tree element not found: ${element}`); + throw new TreeError(this.user, `Tree element not found: ${element}`); } return node; @@ -251,16 +253,15 @@ export class ObjectTreeModel, TFilterData extends Non getParentNodeLocation(element: T | null): T | null { if (element === null) { - throw new Error(`Invalid getParentNodeLocation call`); + throw new TreeError(this.user, `Invalid getParentNodeLocation call`); } - const node = this.nodes.get(element); + const node = this.nodes.get(element)!; + const location = this.model.getNodeLocation(node); + const parentLocation = this.model.getParentNodeLocation(location); + const parent = this.model.getNode(parentLocation); - if (!node) { - throw new Error(`Tree element not found: ${element}`); - } - - return node.parent!.element; + return parent.element; } private getElementLocation(element: T | null): number[] { @@ -271,7 +272,7 @@ export class ObjectTreeModel, TFilterData extends Non const node = this.nodes.get(element); if (!node) { - throw new Error(`Tree element not found: ${element}`); + throw new TreeError(this.user, `Tree element not found: ${element}`); } return this.model.getNodeLocation(node); diff --git a/src/vs/base/browser/ui/tree/tree.ts b/src/vs/base/browser/ui/tree/tree.ts index 1847125b1b..832a4ab2b7 100644 --- a/src/vs/base/browser/ui/tree/tree.ts +++ b/src/vs/base/browser/ui/tree/tree.ts @@ -81,7 +81,6 @@ export interface ITreeElement { export interface ITreeNode { readonly element: T; - readonly parent: ITreeNode | undefined; readonly children: ITreeNode[]; readonly depth: number; readonly visibleChildrenCount: number; @@ -113,13 +112,13 @@ export interface ITreeModel { getListRenderCount(location: TRef): number; getNode(location?: TRef): ITreeNode; getNodeLocation(node: ITreeNode): TRef; - getParentNodeLocation(location: TRef): TRef; + getParentNodeLocation(location: TRef): TRef | undefined; - getParentElement(location: TRef): T; getFirstElementChild(location: TRef): T | undefined; getLastElementAncestor(location?: TRef): T | undefined; isCollapsible(location: TRef): boolean; + setCollapsible(location: TRef, collapsible?: boolean): boolean; isCollapsed(location: TRef): boolean; setCollapsed(location: TRef, collapsed?: boolean, recursive?: boolean): boolean; expandTo(location: TRef): void; @@ -159,7 +158,6 @@ export interface ITreeContextMenuEvent { export interface ITreeNavigator { current(): T | null; previous(): T | null; - parent(): T | null; first(): T | null; last(): T | null; next(): T | null; @@ -194,3 +192,28 @@ export const TreeDragOverReactions = { export interface ITreeDragAndDrop extends IListDragAndDrop { onDragOver(data: IDragAndDropData, targetElement: T | undefined, targetIndex: number | undefined, originalEvent: DragEvent): boolean | ITreeDragOverReaction; } + +export class TreeError extends Error { + + constructor(user: string, message: string) { + super(`TreeError [${user}] ${message}`); + } +} + +export class WeakMapper { + + constructor(private fn: (k: K) => V) { } + + private _map = new WeakMap(); + + map(key: K): V { + let result = this._map.get(key); + + if (!result) { + result = this.fn(key); + this._map.set(key, result); + } + + return result; + } +} diff --git a/src/vs/base/common/amd.ts b/src/vs/base/common/amd.ts index 3854fb0451..0db1d7e074 100644 --- a/src/vs/base/common/amd.ts +++ b/src/vs/base/common/amd.ts @@ -8,3 +8,11 @@ import { URI } from 'vs/base/common/uri'; export function getPathFromAmdModule(requirefn: typeof require, relativePath: string): string { return URI.parse(requirefn.toUrl(relativePath)).fsPath; } + +/** + * Reference a resource that might be inlined. + * Do not rename this method unless you adopt the build scripts. + */ +export function registerAndGetAmdImageURL(absolutePath: string): string { + return require.toUrl(absolutePath); +} diff --git a/src/vs/base/common/collections.ts b/src/vs/base/common/collections.ts index ed2afa0809..5a29b8b300 100644 --- a/src/vs/base/common/collections.ts +++ b/src/vs/base/common/collections.ts @@ -7,17 +7,14 @@ * An interface for a JavaScript object that * acts a dictionary. The keys are strings. */ -export interface IStringDictionary { - [name: string]: V; -} +export type IStringDictionary = Record; + /** * An interface for a JavaScript object that * acts a dictionary. The keys are numbers. */ -export interface INumberDictionary { - [idx: number]: V; -} +export type INumberDictionary = Record; const hasOwnProperty = Object.prototype.hasOwnProperty; @@ -138,4 +135,4 @@ export class SetMap { values.forEach(fn); } -} \ No newline at end of file +} diff --git a/src/vs/base/common/console.ts b/src/vs/base/common/console.ts index 2ade61a6e7..ee6ea6544f 100644 --- a/src/vs/base/common/console.ts +++ b/src/vs/base/common/console.ts @@ -114,9 +114,9 @@ export function log(entry: IRemoteConsoleLog, label: string): void { // First arg is a string if (typeof args[0] === 'string') { if (topFrame && isOneStringArg) { - consoleArgs = [`%c[${label}] %c${args[0]} %c${topFrame}`, color('blue'), color('black'), color('grey')]; + consoleArgs = [`%c[${label}] %c${args[0]} %c${topFrame}`, color('blue'), color(''), color('grey')]; } else { - consoleArgs = [`%c[${label}] %c${args[0]}`, color('blue'), color('black'), ...args.slice(1)]; + consoleArgs = [`%c[${label}] %c${args[0]}`, color('blue'), color(''), ...args.slice(1)]; } } @@ -139,4 +139,4 @@ export function log(entry: IRemoteConsoleLog, label: string): void { function color(color: string): string { return `color: ${color}`; -} \ No newline at end of file +} diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index d49c7f589b..ff688e0986 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -455,6 +455,14 @@ function printTable(table: number[][], pattern: string, patternLen: number, word return ret; } +function printTables(pattern: string, patternStart: number, word: string, wordStart: number): void { + pattern = pattern.substr(patternStart); + word = word.substr(wordStart); + console.log(printTable(_table, pattern, pattern.length, word, word.length)); + console.log(printTable(_arrows, pattern, pattern.length, word, word.length)); + console.log(printTable(_scores, pattern, pattern.length, word, word.length)); +} + function isSeparatorAtPos(value: string, index: number): boolean { if (index < 0 || index >= value.length) { return false; @@ -530,130 +538,127 @@ export interface FuzzyScorer { (pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number, firstMatchCanBeWeak: boolean): FuzzyScore | undefined; } -export function fuzzyScore(pattern: string, patternLow: string, patternPos: number, word: string, wordLow: string, wordPos: number, firstMatchCanBeWeak: boolean): FuzzyScore | undefined { - - if (patternPos > 0) { - pattern = pattern.substr(patternPos); - patternLow = patternLow.substr(patternPos); - patternPos = 0; - } +export function fuzzyScore(pattern: string, patternLow: string, patternStart: number, word: string, wordLow: string, wordStart: number, firstMatchCanBeWeak: boolean): FuzzyScore | undefined { const patternLen = pattern.length > _maxLen ? _maxLen : pattern.length; const wordLen = word.length > _maxLen ? _maxLen : word.length; - if (patternPos >= patternLen || wordPos >= wordLen || patternLen > wordLen) { + if (patternStart >= patternLen || wordStart >= wordLen || patternLen > wordLen) { return undefined; } // Run a simple check if the characters of pattern occur // (in order) at all in word. If that isn't the case we // stop because no match will be possible - if (!isPatternInWord(patternLow, patternPos, patternLen, wordLow, wordPos, wordLen)) { + if (!isPatternInWord(patternLow, patternStart, patternLen, wordLow, wordStart, wordLen)) { return undefined; } - const patternStartPos = patternPos; - const wordStartPos = wordPos; + let row: number = 1; + let column: number = 1; + let patternPos = patternStart; + let wordPos = wordStart; // There will be a match, fill in tables - for (patternPos = patternStartPos + 1; patternPos <= patternLen; patternPos++) { + for (row = 1, patternPos = patternStart; patternPos < patternLen; row++ , patternPos++) { - for (wordPos = 1; wordPos <= wordLen; wordPos++) { + for (column = 1, wordPos = wordStart; wordPos < wordLen; column++ , wordPos++) { - let score = -1; - if (patternLow[patternPos - 1] === wordLow[wordPos - 1]) { + const score = _doScore(pattern, patternLow, patternPos, patternStart, word, wordLow, wordPos); - if (wordPos === (patternPos - patternStartPos)) { - // common prefix: `foobar <-> foobaz` - // ^^^^^ - if (pattern[patternPos - 1] === word[wordPos - 1]) { - score = 7; - } else { - score = 5; - } - } else if (isUpperCaseAtPos(wordPos - 1, word, wordLow) && (wordPos === 1 || !isUpperCaseAtPos(wordPos - 2, word, wordLow))) { - // hitting upper-case: `foo <-> forOthers` - // ^^ ^ - if (pattern[patternPos - 1] === word[wordPos - 1]) { - score = 7; - } else { - score = 5; - } - } else if (isSeparatorAtPos(wordLow, wordPos - 1) && (wordPos === 1 || !isSeparatorAtPos(wordLow, wordPos - 2))) { - // hitting a separator: `. <-> foo.bar` - // ^ - score = 5; + _scores[row][column] = score; - } else if (isSeparatorAtPos(wordLow, wordPos - 2) || isWhitespaceAtPos(wordLow, wordPos - 2)) { - // post separator: `foo <-> bar_foo` - // ^^^ - score = 5; - - } else { - score = 1; - } - } - - _scores[patternPos][wordPos] = score; - - const diag = _table[patternPos - 1][wordPos - 1] + (score > 1 ? 1 : score); - const top = _table[patternPos - 1][wordPos] + -1; - const left = _table[patternPos][wordPos - 1] + -1; + const diag = _table[row - 1][column - 1] + (score > 1 ? 1 : score); + const top = _table[row - 1][column] + -1; + const left = _table[row][column - 1] + -1; if (left >= top) { // left or diag if (left > diag) { - _table[patternPos][wordPos] = left; - _arrows[patternPos][wordPos] = Arrow.Left; + _table[row][column] = left; + _arrows[row][column] = Arrow.Left; } else if (left === diag) { - _table[patternPos][wordPos] = left; - _arrows[patternPos][wordPos] = Arrow.Left | Arrow.Diag; + _table[row][column] = left; + _arrows[row][column] = Arrow.Left | Arrow.Diag; } else { - _table[patternPos][wordPos] = diag; - _arrows[patternPos][wordPos] = Arrow.Diag; + _table[row][column] = diag; + _arrows[row][column] = Arrow.Diag; } } else { // top or diag if (top > diag) { - _table[patternPos][wordPos] = top; - _arrows[patternPos][wordPos] = Arrow.Top; + _table[row][column] = top; + _arrows[row][column] = Arrow.Top; } else if (top === diag) { - _table[patternPos][wordPos] = top; - _arrows[patternPos][wordPos] = Arrow.Top | Arrow.Diag; + _table[row][column] = top; + _arrows[row][column] = Arrow.Top | Arrow.Diag; } else { - _table[patternPos][wordPos] = diag; - _arrows[patternPos][wordPos] = Arrow.Diag; + _table[row][column] = diag; + _arrows[row][column] = Arrow.Diag; } } } } if (_debug) { - console.log(printTable(_table, pattern, patternLen, word, wordLen)); - console.log(printTable(_arrows, pattern, patternLen, word, wordLen)); - console.log(printTable(_scores, pattern, patternLen, word, wordLen)); + printTables(pattern, patternStart, word, wordStart); } _matchesCount = 0; _topScore = -100; - _patternStartPos = patternStartPos; + _wordStart = wordStart; _firstMatchCanBeWeak = firstMatchCanBeWeak; - _findAllMatches2(patternLen, wordLen, patternLen === wordLen ? 1 : 0, 0, false); + + _findAllMatches2(row - 1, column - 1, patternLen === wordLen ? 1 : 0, 0, false); if (_matchesCount === 0) { return undefined; } - return [_topScore, _topMatch2, wordStartPos]; + return [_topScore, _topMatch2, wordStart]; } +function _doScore(pattern: string, patternLow: string, patternPos: number, patternStart: number, word: string, wordLow: string, wordPos: number) { + if (patternLow[patternPos] !== wordLow[wordPos]) { + return -1; + } + if (wordPos === (patternPos - patternStart)) { + // common prefix: `foobar <-> foobaz` + // ^^^^^ + if (pattern[patternPos] === word[wordPos]) { + return 7; + } else { + return 5; + } + } else if (isUpperCaseAtPos(wordPos, word, wordLow) && (wordPos === 0 || !isUpperCaseAtPos(wordPos - 1, word, wordLow))) { + // hitting upper-case: `foo <-> forOthers` + // ^^ ^ + if (pattern[patternPos] === word[wordPos]) { + return 7; + } else { + return 5; + } + } else if (isSeparatorAtPos(wordLow, wordPos) && (wordPos === 0 || !isSeparatorAtPos(wordLow, wordPos - 1))) { + // hitting a separator: `. <-> foo.bar` + // ^ + return 5; + + } else if (isSeparatorAtPos(wordLow, wordPos - 1) || isWhitespaceAtPos(wordLow, wordPos - 1)) { + // post separator: `foo <-> bar_foo` + // ^^^ + return 5; + + } else { + return 1; + } +} let _matchesCount: number = 0; let _topMatch2: number = 0; let _topScore: number = 0; -let _patternStartPos: number = 0; +let _wordStart: number = 0; let _firstMatchCanBeWeak: boolean = false; -function _findAllMatches2(patternPos: number, wordPos: number, total: number, matches: number, lastMatched: boolean): void { +function _findAllMatches2(row: number, column: number, total: number, matches: number, lastMatched: boolean): void { if (_matchesCount >= 10 || total < -25) { // stop when having already 10 results, or @@ -663,14 +668,14 @@ function _findAllMatches2(patternPos: number, wordPos: number, total: number, ma let simpleMatchCount = 0; - while (patternPos > _patternStartPos && wordPos > 0) { + while (row > 0 && column > 0) { - const score = _scores[patternPos][wordPos]; - const arrow = _arrows[patternPos][wordPos]; + const score = _scores[row][column]; + const arrow = _arrows[row][column]; if (arrow === Arrow.Left) { // left -> no match, skip a word character - wordPos -= 1; + column -= 1; if (lastMatched) { total -= 5; // new gap penalty } else if (matches !== 0) { @@ -684,8 +689,8 @@ function _findAllMatches2(patternPos: number, wordPos: number, total: number, ma if (arrow & Arrow.Left) { // left _findAllMatches2( - patternPos, - wordPos - 1, + row, + column - 1, matches !== 0 ? total - 1 : total, // gap penalty after first match matches, lastMatched @@ -694,12 +699,12 @@ function _findAllMatches2(patternPos: number, wordPos: number, total: number, ma // diag total += score; - patternPos -= 1; - wordPos -= 1; + row -= 1; + column -= 1; lastMatched = true; // match -> set a 1 at the word pos - matches += 2 ** wordPos; + matches += 2 ** (column + _wordStart); // count simple matches and boost a row of // simple matches when they yield in a @@ -707,7 +712,7 @@ function _findAllMatches2(patternPos: number, wordPos: number, total: number, ma if (score === 1) { simpleMatchCount += 1; - if (patternPos === _patternStartPos && !_firstMatchCanBeWeak) { + if (row === 0 && !_firstMatchCanBeWeak) { // when the first match is a weak // match we discard it return undefined; @@ -724,7 +729,7 @@ function _findAllMatches2(patternPos: number, wordPos: number, total: number, ma } } - total -= wordPos >= 3 ? 9 : wordPos * 3; // late start penalty + total -= column >= 3 ? 9 : column * 3; // late start penalty // dynamically keep track of the current top score // and insert the current best score at head, the rest at tail diff --git a/src/vs/base/common/json.ts b/src/vs/base/common/json.ts index 779118466b..9da1277bc8 100644 --- a/src/vs/base/common/json.ts +++ b/src/vs/base/common/json.ts @@ -207,17 +207,17 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON function scanHexDigits(count: number): number { let digits = 0; - let value = 0; + let hexValue = 0; while (digits < count) { const ch = text.charCodeAt(pos); if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) { - value = value * 16 + ch - CharacterCodes._0; + hexValue = hexValue * 16 + ch - CharacterCodes._0; } else if (ch >= CharacterCodes.A && ch <= CharacterCodes.F) { - value = value * 16 + ch - CharacterCodes.A + 10; + hexValue = hexValue * 16 + ch - CharacterCodes.A + 10; } else if (ch >= CharacterCodes.a && ch <= CharacterCodes.f) { - value = value * 16 + ch - CharacterCodes.a + 10; + hexValue = hexValue * 16 + ch - CharacterCodes.a + 10; } else { break; @@ -226,9 +226,9 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON digits++; } if (digits < count) { - value = -1; + hexValue = -1; } - return value; + return hexValue; } function setPosition(newPosition: number) { @@ -291,7 +291,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON scanError = ScanError.UnexpectedEndOfString; break; } - let ch = text.charCodeAt(pos); + const ch = text.charCodeAt(pos); if (ch === CharacterCodes.doubleQuote) { result += text.substring(start, pos); pos++; @@ -304,8 +304,8 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON scanError = ScanError.UnexpectedEndOfString; break; } - ch = text.charCodeAt(pos++); - switch (ch) { + const ch2 = text.charCodeAt(pos++); + switch (ch2) { case CharacterCodes.doubleQuote: result += '\"'; break; @@ -331,9 +331,9 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON result += '\t'; break; case CharacterCodes.u: - const ch = scanHexDigits(4); - if (ch >= 0) { - result += String.fromCharCode(ch); + const ch3 = scanHexDigits(4); + if (ch3 >= 0) { + result += String.fromCharCode(ch3); } else { scanError = ScanError.InvalidUnicode; } @@ -1340,4 +1340,4 @@ function getLiteralNodeType(value: any): NodeType { case 'string': return 'string'; default: return 'null'; } -} \ No newline at end of file +} diff --git a/src/vs/base/common/jsonEdit.ts b/src/vs/base/common/jsonEdit.ts index dc8f902313..1de95c55c0 100644 --- a/src/vs/base/common/jsonEdit.ts +++ b/src/vs/base/common/jsonEdit.ts @@ -144,11 +144,11 @@ function withFormatting(text: string, edit: Edit, formattingOptions: FormattingO // apply the formatting edits and track the begin and end offsets of the changes for (let i = edits.length - 1; i >= 0; i--) { - const edit = edits[i]; - newText = applyEdit(newText, edit); - begin = Math.min(begin, edit.offset); - end = Math.max(end, edit.offset + edit.length); - end += edit.content.length - edit.length; + const curr = edits[i]; + newText = applyEdit(newText, curr); + begin = Math.min(begin, curr.offset); + end = Math.max(end, curr.offset + curr.length); + end += curr.content.length - curr.length; } // create a single edit with all changes const editLength = text.length - (newText.length - end) - begin; @@ -182,4 +182,4 @@ export function applyEdits(text: string, edits: Edit[]): string { export function isWS(text: string, offset: number) { return '\r\n \t'.indexOf(text.charAt(offset)) !== -1; -} \ No newline at end of file +} diff --git a/src/vs/base/common/jsonSchema.ts b/src/vs/base/common/jsonSchema.ts index 88d3834f98..2796d1cb7b 100644 --- a/src/vs/base/common/jsonSchema.ts +++ b/src/vs/base/common/jsonSchema.ts @@ -61,6 +61,7 @@ export interface IJSONSchema { markdownDescription?: string; // VSCode extension doNotSuggest?: boolean; // VSCode extension allowComments?: boolean; // VSCode extension + allowsTrailingCommas?: boolean; // VSCode extension } export interface IJSONSchemaMap { diff --git a/src/vs/base/common/labels.ts b/src/vs/base/common/labels.ts index b8fe94b85c..9873c8d76d 100644 --- a/src/vs/base/common/labels.ts +++ b/src/vs/base/common/labels.ts @@ -283,7 +283,7 @@ interface ISegment { * @param value string to which templating is applied * @param values the values of the templates to use */ -export function template(template: string, values: { [key: string]: string | ISeparator | null } = Object.create(null)): string { +export function template(template: string, values: { [key: string]: string | ISeparator | undefined | null } = Object.create(null)): string { const segments: ISegment[] = []; let inVariable = false; diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index 1e07043d5a..a8c49969ec 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -18,7 +18,7 @@ export function values(forEachable: { forEach(callback: (value: V, ...more: a export function keys(map: Map): K[] { const result: K[] = []; - map.forEach((value, key) => result.push(key)); + map.forEach((_value, key) => result.push(key)); return result; } @@ -482,8 +482,6 @@ export class ResourceMap { } } -// We should fold BoundedMap and LinkedMap. See https://github.com/Microsoft/vscode/issues/28496 - interface Item { previous: Item | undefined; next: Item | undefined; diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index 29255182d1..6a579f0bbf 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI } from 'vs/base/common/uri'; +import { URI, UriComponents } from 'vs/base/common/uri'; import * as platform from 'vs/base/common/platform'; export namespace Schemas { @@ -60,18 +60,24 @@ class RemoteAuthoritiesImpl { private readonly _ports: { [authority: string]: number; }; private readonly _connectionTokens: { [authority: string]: string; }; private _preferredWebSchema: 'http' | 'https'; + private _delegate: ((uri: URI) => UriComponents) | null; constructor() { this._hosts = Object.create(null); this._ports = Object.create(null); this._connectionTokens = Object.create(null); this._preferredWebSchema = 'http'; + this._delegate = null; } public setPreferredWebSchema(schema: 'http' | 'https') { this._preferredWebSchema = schema; } + public setDelegate(delegate: (uri: URI) => UriComponents): void { + this._delegate = delegate; + } + public set(authority: string, host: string, port: number): void { this._hosts[authority] = host; this._ports[authority] = port; @@ -81,7 +87,12 @@ class RemoteAuthoritiesImpl { this._connectionTokens[authority] = connectionToken; } - public rewrite(authority: string, path: string): URI { + public rewrite(uri: URI): URI { + if (this._delegate) { + const result = this._delegate(uri); + return URI.revive(result); + } + const authority = uri.authority; const host = this._hosts[authority]; const port = this._ports[authority]; const connectionToken = this._connectionTokens[authority]; @@ -89,7 +100,7 @@ class RemoteAuthoritiesImpl { scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource, authority: `${host}:${port}`, path: `/vscode-remote-resource`, - query: `path=${encodeURIComponent(path)}&tkn=${encodeURIComponent(connectionToken)}` + query: `path=${encodeURIComponent(uri.path)}&tkn=${encodeURIComponent(connectionToken)}` }); } } diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts index 97962916e6..90bd19e2df 100644 --- a/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts @@ -156,20 +156,21 @@ export const translationsConfigFile = _translationsConfigFile; const _globals = (typeof self === 'object' ? self : typeof global === 'object' ? global : {} as any); export const globals: any = _globals; -let _setImmediate: ((callback: (...args: any[]) => void) => number) | null = null; -export function setImmediate(callback: (...args: any[]) => void): number { - if (_setImmediate === null) { - if (globals.setImmediate) { - _setImmediate = globals.setImmediate.bind(globals); - } else if (typeof process !== 'undefined' && typeof process.nextTick === 'function') { - _setImmediate = process.nextTick.bind(process); - } else { - _setImmediate = globals.setTimeout.bind(globals); - } - } - return _setImmediate!(callback); +interface ISetImmediate { + (callback: (...args: any[]) => void): void; } +export const setImmediate: ISetImmediate = (function defineSetImmediate() { + if (globals.setImmediate) { + return globals.setImmediate.bind(globals); + } + if (typeof process !== 'undefined' && typeof process.nextTick === 'function') { + return process.nextTick.bind(process); + } + const _promise = Promise.resolve(); + return (callback: (...args: any[]) => void) => _promise.then(callback); +})(); + export const enum OperatingSystem { Windows = 1, Macintosh = 2, diff --git a/src/vs/base/common/process.ts b/src/vs/base/common/process.ts index b9e65fe79d..463f327990 100644 --- a/src/vs/base/common/process.ts +++ b/src/vs/base/common/process.ts @@ -10,7 +10,7 @@ interface IProcess { env: IProcessEnvironment; cwd(): string; - nextTick(callback: (...args: any[]) => void): number; + nextTick(callback: (...args: any[]) => void): void; } declare const process: IProcess; @@ -18,7 +18,7 @@ const safeProcess: IProcess = (typeof process === 'undefined') ? { cwd(): string { return '/'; }, env: Object.create(null), get platform(): string { return isWindows ? 'win32' : isMacintosh ? 'darwin' : 'linux'; }, - nextTick(callback: (...args: any[]) => void): number { return setImmediate(callback); } + nextTick(callback: (...args: any[]) => void): void { return setImmediate(callback); } } : process; export const cwd = safeProcess.cwd; diff --git a/src/vs/base/common/search.ts b/src/vs/base/common/search.ts index 6fb11a17c0..892aa45eab 100644 --- a/src/vs/base/common/search.ts +++ b/src/vs/base/common/search.ts @@ -12,8 +12,12 @@ export function buildReplaceStringWithCasePreserved(matches: string[] | null, pa } else if (matches[0].toLowerCase() === matches[0]) { return pattern.toLowerCase(); } else if (strings.containsUppercaseCharacter(matches[0][0])) { - if (validateSpecificSpecialCharacter(matches, pattern, '-')) { + const containsHyphens = validateSpecificSpecialCharacter(matches, pattern, '-'); + const containsUnderscores = validateSpecificSpecialCharacter(matches, pattern, '_'); + if (containsHyphens && !containsUnderscores) { return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '-'); + } else if (!containsHyphens && containsUnderscores) { + return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '_'); } else { return pattern[0].toUpperCase() + pattern.substr(1); } @@ -27,8 +31,8 @@ export function buildReplaceStringWithCasePreserved(matches: string[] | null, pa } function validateSpecificSpecialCharacter(matches: string[], pattern: string, specialCharacter: string): boolean { - const doesConatinSpecialCharacter = matches[0].indexOf(specialCharacter) !== -1 && pattern.indexOf(specialCharacter) !== -1; - return doesConatinSpecialCharacter && matches[0].split(specialCharacter).length === pattern.split(specialCharacter).length; + const doesContainSpecialCharacter = matches[0].indexOf(specialCharacter) !== -1 && pattern.indexOf(specialCharacter) !== -1; + return doesContainSpecialCharacter && matches[0].split(specialCharacter).length === pattern.split(specialCharacter).length; } function buildReplaceStringForSpecificSpecialCharacter(matches: string[], pattern: string, specialCharacter: string): string { diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 9305b25cae..84de11eddf 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -5,11 +5,6 @@ import { CharCode } from 'vs/base/common/charCode'; -/** - * The empty string. - */ -export const empty = ''; - export function isFalsyOrWhitespace(str: string | undefined): boolean { if (!str || typeof str !== 'string') { return true; @@ -70,7 +65,7 @@ export function escape(html: string): string { * Escapes regular expression characters in a given string */ export function escapeRegExpCharacters(value: string): string { - return value.replace(/[\-\\\{\}\*\+\?\|\^\$\.\[\]\(\)\#]/g, '\\$&'); + return value.replace(/[\\\{\}\*\+\?\|\^\$\.\[\]\(\)]/g, '\\$&'); } /** @@ -608,7 +603,7 @@ export function lcut(text: string, n: number) { re.lastIndex += 1; } - return text.substring(i).replace(/^\s/, empty); + return text.substring(i).replace(/^\s/, ''); } // Escape codes @@ -636,7 +631,7 @@ export const removeAccents: (str: string) => string = (function () { // see: https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript/37511463#37511463 const regex = /[\u0300-\u036f]/g; return function (str: string) { - return (str as any).normalize('NFD').replace(regex, empty); + return (str as any).normalize('NFD').replace(regex, ''); }; } })(); diff --git a/src/vs/base/node/config.ts b/src/vs/base/node/config.ts index 1f861e37de..8dcb97d410 100644 --- a/src/vs/base/node/config.ts +++ b/src/vs/base/node/config.ts @@ -42,11 +42,11 @@ export interface IConfigOptions { * - configurable defaults */ export class ConfigWatcher extends Disposable implements IConfigWatcher { - private cache: T; - private parseErrors: json.ParseError[]; - private disposed: boolean; - private loaded: boolean; - private timeoutHandle: NodeJS.Timer | null; + private cache: T | undefined; + private parseErrors: json.ParseError[] | undefined; + private disposed: boolean | undefined; + private loaded: boolean | undefined; + private timeoutHandle: NodeJS.Timer | null | undefined; private readonly _onDidUpdateConfiguration: Emitter>; constructor(private _path: string, private options: IConfigOptions = { defaultConfig: Object.create(null), onError: error => console.error(error) }) { @@ -62,7 +62,7 @@ export class ConfigWatcher extends Disposable implements IConfigWatcher { } get hasParseErrors(): boolean { - return this.parseErrors && this.parseErrors.length > 0; + return !!this.parseErrors && this.parseErrors.length > 0; } get onDidUpdateConfiguration(): Event> { @@ -161,7 +161,7 @@ export class ConfigWatcher extends Disposable implements IConfigWatcher { if (!objects.equals(currentConfig, this.cache)) { this.updateCache(currentConfig); - this._onDidUpdateConfiguration.fire({ config: this.cache }); + this._onDidUpdateConfiguration.fire({ config: currentConfig }); } if (callback) { @@ -173,7 +173,7 @@ export class ConfigWatcher extends Disposable implements IConfigWatcher { getConfig(): T { this.ensureLoaded(); - return this.cache; + return this.cache!; } private ensureLoaded(): void { @@ -186,4 +186,4 @@ export class ConfigWatcher extends Disposable implements IConfigWatcher { this.disposed = true; super.dispose(); } -} \ No newline at end of file +} diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js index 278242dc2c..c63e26f401 100644 --- a/src/vs/base/node/languagePacks.js +++ b/src/vs/base/node/languagePacks.js @@ -268,10 +268,10 @@ function factory(nodeRequire, path, fs, perf) { const packData = JSON.parse(values[1]).contents; const bundles = Object.keys(metadata.bundles); const writes = []; - for (let bundle of bundles) { + for (const bundle of bundles) { const modules = metadata.bundles[bundle]; const target = Object.create(null); - for (let module of modules) { + for (const module of modules) { const keys = metadata.keys[module]; const defaultMessages = metadata.messages[module]; const translations = packData[module]; diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index 206b6a03d0..9bf50bb89c 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -258,15 +258,15 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { filter: new Filter(this), accessibilityProvider: new AccessibilityProvider(this) }, { - twistiePixels: 11, - indentPixels: 0, - alwaysFocused: true, - verticalScrollMode: ScrollbarVisibility.Visible, - horizontalScrollMode: ScrollbarVisibility.Hidden, - ariaLabel: nls.localize('treeAriaLabel', "Quick Picker"), - keyboardSupport: this.options.keyboardSupport, - preventRootFocus: false - })); + twistiePixels: 11, + indentPixels: 0, + alwaysFocused: true, + verticalScrollMode: ScrollbarVisibility.Visible, + horizontalScrollMode: ScrollbarVisibility.Hidden, + ariaLabel: nls.localize('treeAriaLabel', "Quick Picker"), + keyboardSupport: this.options.keyboardSupport, + preventRootFocus: false + })); this.treeElement = this.tree.getHTMLElement(); diff --git a/src/vs/base/parts/storage/node/storage.ts b/src/vs/base/parts/storage/node/storage.ts index 42a597d1a6..4d4d812f77 100644 --- a/src/vs/base/parts/storage/node/storage.ts +++ b/src/vs/base/parts/storage/node/storage.ts @@ -420,8 +420,8 @@ export class SQLiteStorageDatabase implements IStorageDatabase { } class SQLiteStorageDatabaseLogger { - private readonly logTrace: (msg: string) => void; - private readonly logError: (error: string | Error) => void; + private readonly logTrace: ((msg: string) => void) | undefined; + private readonly logError: ((error: string | Error) => void) | undefined; constructor(options?: ISQLiteStorageDatabaseLoggingOptions) { if (options && typeof options.logTrace === 'function') { diff --git a/src/vs/base/parts/tree/browser/treeImpl.ts b/src/vs/base/parts/tree/browser/treeImpl.ts index 40d70cee3d..4ea61da4b2 100644 --- a/src/vs/base/parts/tree/browser/treeImpl.ts +++ b/src/vs/base/parts/tree/browser/treeImpl.ts @@ -110,15 +110,15 @@ export class Tree implements _.ITree { } get onDidFocus(): Event { - return this.view && this.view.onDOMFocus; + return this.view.onDOMFocus; } get onDidBlur(): Event { - return this.view && this.view.onDOMBlur; + return this.view.onDOMBlur; } get onDidScroll(): Event { - return this.view && this.view.onDidScroll; + return this.view.onDidScroll; } public getHTMLElement(): HTMLElement { @@ -300,16 +300,8 @@ export class Tree implements _.ITree { public dispose(): void { this._onDispose.fire(); - - if (this.model !== null) { - this.model.dispose(); - this.model = null!; // StrictNullOverride Nulling out ok in dispose - } - if (this.view !== null) { - this.view.dispose(); - this.view = null!; // StrictNullOverride Nulling out ok in dispose - } - + this.model.dispose(); + this.view.dispose(); this._onDidChangeFocus.dispose(); this._onDidChangeSelection.dispose(); this._onHighlightChange.dispose(); diff --git a/src/vs/base/parts/tree/browser/treeModel.ts b/src/vs/base/parts/tree/browser/treeModel.ts index d547e96951..33c6d39e88 100644 --- a/src/vs/base/parts/tree/browser/treeModel.ts +++ b/src/vs/base/parts/tree/browser/treeModel.ts @@ -5,7 +5,7 @@ import * as Assert from 'vs/base/common/assert'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, combinedDisposable, Disposable } from 'vs/base/common/lifecycle'; import { INavigator } from 'vs/base/common/iterator'; import * as _ from './tree'; import { Event, Emitter, EventMultiplexer, Relay } from 'vs/base/common/event'; @@ -192,7 +192,7 @@ export class ItemRegistry { } public dispose(): void { - this.items = null!; // StrictNullOverride: nulling out ok in dispose + this.items = {}; this._onDidRevealItem.dispose(); this._onExpandItem.dispose(); @@ -864,8 +864,8 @@ export class TreeModel { private context: _.ITreeContext; private lock!: Lock; private input: Item | null; - private registry!: ItemRegistry; - private registryDisposable!: IDisposable; + private registry: ItemRegistry = new ItemRegistry(); + private registryDisposable: IDisposable = Disposable.None; private traitsToItems: ITraitMap; private _onSetInput = new Emitter(); @@ -1471,11 +1471,7 @@ export class TreeModel { } public dispose(): void { - if (this.registry) { - this.registry.dispose(); - this.registry = null!; // StrictNullOverride: nulling out ok in dispose - } - + this.registry.dispose(); this._onSetInput.dispose(); this._onDidSetInput.dispose(); this._onRefresh.dispose(); diff --git a/src/vs/base/parts/tree/browser/treeView.ts b/src/vs/base/parts/tree/browser/treeView.ts index a1a34dab35..c4df0db57e 100644 --- a/src/vs/base/parts/tree/browser/treeView.ts +++ b/src/vs/base/parts/tree/browser/treeView.ts @@ -927,9 +927,9 @@ export class TreeView extends HeightMap { getLength: () => previousChildrenIds.length, getElementAtIndex: (i: number) => previousChildrenIds[i] }, { - getLength: () => afterModelItems.length, - getElementAtIndex: (i: number) => afterModelItems[i].id - }, + getLength: () => afterModelItems.length, + getElementAtIndex: (i: number) => afterModelItems[i].id + }, null ); diff --git a/src/vs/base/test/browser/ui/list/rangeMap.test.ts b/src/vs/base/test/browser/ui/list/rangeMap.test.ts index af6ffc17ce..522a859ac6 100644 --- a/src/vs/base/test/browser/ui/list/rangeMap.test.ts +++ b/src/vs/base/test/browser/ui/list/rangeMap.test.ts @@ -14,10 +14,6 @@ suite('RangeMap', () => { rangeMap = new RangeMap(); }); - teardown(() => { - rangeMap.dispose(); - }); - test('intersection', () => { assert.deepEqual(Range.intersect({ start: 0, end: 0 }, { start: 0, end: 0 }), { start: 0, end: 0 }); assert.deepEqual(Range.intersect({ start: 0, end: 0 }, { start: 5, end: 5 }), { start: 0, end: 0 }); @@ -346,4 +342,4 @@ suite('RangeMap', () => { assert.equal(rangeMap.positionAt(4), -1); }); }); -}); \ No newline at end of file +}); diff --git a/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts b/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts index 97bbcc921c..85fc0d82ac 100644 --- a/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts +++ b/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts @@ -8,6 +8,7 @@ import { ITreeNode, ITreeRenderer, IAsyncDataSource } from 'vs/base/browser/ui/t import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list'; import { hasClass } from 'vs/base/browser/dom'; +import { timeout } from 'vs/base/common/async'; interface Element { id: string; @@ -26,104 +27,89 @@ function find(elements: Element[] | undefined, id: string): Element { throw new Error('element not found'); } +class Renderer implements ITreeRenderer { + readonly templateId = 'default'; + renderTemplate(container: HTMLElement): HTMLElement { + return container; + } + renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { + templateData.textContent = element.element.id; + } + disposeTemplate(templateData: HTMLElement): void { + // noop + } +} + +class IdentityProvider implements IIdentityProvider { + getId(element: Element) { + return element.id; + } +} + +class VirtualDelegate implements IListVirtualDelegate { + getHeight() { return 20; } + getTemplateId(element: Element): string { return 'default'; } +} + +class DataSource implements IAsyncDataSource { + hasChildren(element: Element): boolean { + return !!element.children && element.children.length > 0; + } + getChildren(element: Element): Promise { + return Promise.resolve(element.children || []); + } +} + +class Model { + + constructor(readonly root: Element) { } + + get(id: string): Element { + return find(this.root.children, id); + } +} + suite('AsyncDataTree', function () { test('Collapse state should be preserved across refresh calls', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; - - const dataSource = new class implements IAsyncDataSource { - hasChildren(element: Element): boolean { - return !!element.children && element.children.length > 0; - } - getChildren(element: Element): Promise { - return Promise.resolve(element.children || []); - } - }; - - const identityProvider = new class implements IIdentityProvider { - getId(element: Element) { - return element.id; - } - }; - - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a' }] - }; + }); - const _: (id: string) => Element = find.bind(null, root.children); - - const tree = new AsyncDataTree(container, delegate, [renderer], dataSource, { identityProvider }); + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], new DataSource(), { identityProvider: new IdentityProvider() }); tree.layout(200); assert.equal(container.querySelectorAll('.monaco-list-row').length, 0); - await tree.setInput(root); + await tree.setInput(model.root); assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; assert(!hasClass(twistie, 'collapsible')); assert(!hasClass(twistie, 'collapsed')); - _('a').children = [ + model.get('a').children = [ { id: 'aa' }, { id: 'ab' }, { id: 'ac' } ]; - await tree.updateChildren(root); + await tree.updateChildren(model.root); assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); - await tree.expand(_('a')); + await tree.expand(model.get('a')); assert.equal(container.querySelectorAll('.monaco-list-row').length, 4); - _('a').children = []; - await tree.updateChildren(root); + model.get('a').children = []; + await tree.updateChildren(model.root); assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); }); test('issue #68648', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; const getChildrenCalls: string[] = []; const dataSource = new class implements IAsyncDataSource { @@ -136,25 +122,17 @@ suite('AsyncDataTree', function () { } }; - const identityProvider = new class implements IIdentityProvider { - getId(element: Element) { - return element.id; - } - }; - - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a' }] - }; + }); - const _: (id: string) => Element = find.bind(null, root.children); - - const tree = new AsyncDataTree(container, delegate, [renderer], dataSource, { identityProvider }); + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); tree.layout(200); - await tree.setInput(root); + await tree.setInput(model.root); assert.deepStrictEqual(getChildrenCalls, ['root']); let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; @@ -162,8 +140,8 @@ suite('AsyncDataTree', function () { assert(!hasClass(twistie, 'collapsed')); assert(tree.getNode().children[0].collapsed); - _('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]; - await tree.updateChildren(root); + model.get('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]; + await tree.updateChildren(model.root); assert.deepStrictEqual(getChildrenCalls, ['root', 'root']); twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; @@ -171,8 +149,8 @@ suite('AsyncDataTree', function () { assert(hasClass(twistie, 'collapsed')); assert(tree.getNode().children[0].collapsed); - _('a').children = []; - await tree.updateChildren(root); + model.get('a').children = []; + await tree.updateChildren(model.root); assert.deepStrictEqual(getChildrenCalls, ['root', 'root', 'root']); twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; @@ -180,8 +158,8 @@ suite('AsyncDataTree', function () { assert(!hasClass(twistie, 'collapsed')); assert(tree.getNode().children[0].collapsed); - _('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]; - await tree.updateChildren(root); + model.get('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]; + await tree.updateChildren(model.root); assert.deepStrictEqual(getChildrenCalls, ['root', 'root', 'root', 'root']); twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; @@ -192,26 +170,6 @@ suite('AsyncDataTree', function () { test('issue #67722 - once resolved, refreshed collapsed nodes should only get children when expanded', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; const getChildrenCalls: string[] = []; const dataSource = new class implements IAsyncDataSource { @@ -224,131 +182,66 @@ suite('AsyncDataTree', function () { } }; - const identityProvider = new class implements IIdentityProvider { - getId(element: Element) { - return element.id; - } - }; - - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a', children: [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }] }] - }; + }); - const _: (id: string) => Element = find.bind(null, root.children); - - const tree = new AsyncDataTree(container, delegate, [renderer], dataSource, { identityProvider }); + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); tree.layout(200); - await tree.setInput(root); - assert(tree.getNode(_('a')).collapsed); + await tree.setInput(model.root); + assert(tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root']); - await tree.expand(_('a')); - assert(!tree.getNode(_('a')).collapsed); + await tree.expand(model.get('a')); + assert(!tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root', 'a']); - tree.collapse(_('a')); - assert(tree.getNode(_('a')).collapsed); + tree.collapse(model.get('a')); + assert(tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root', 'a']); await tree.updateChildren(); - assert(tree.getNode(_('a')).collapsed); + assert(tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root', 'a', 'root'], 'a should not be refreshed, since it\' collapsed'); }); test('resolved collapsed nodes which lose children should lose twistie as well', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; - - const dataSource = new class implements IAsyncDataSource { - hasChildren(element: Element): boolean { - return !!element.children && element.children.length > 0; - } - getChildren(element: Element): Promise { - return Promise.resolve(element.children || []); - } - }; - - const identityProvider = new class implements IIdentityProvider { - getId(element: Element) { - return element.id; - } - }; - - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a', children: [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }] }] - }; + }); - const _: (id: string) => Element = find.bind(null, root.children); - - const tree = new AsyncDataTree(container, delegate, [renderer], dataSource, { identityProvider }); + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], new DataSource(), { identityProvider: new IdentityProvider() }); tree.layout(200); - await tree.setInput(root); - await tree.expand(_('a')); + await tree.setInput(model.root); + await tree.expand(model.get('a')); let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; assert(hasClass(twistie, 'collapsible')); assert(!hasClass(twistie, 'collapsed')); - assert(!tree.getNode(_('a')).collapsed); + assert(!tree.getNode(model.get('a')).collapsed); - tree.collapse(_('a')); - _('a').children = []; - await tree.updateChildren(root); + tree.collapse(model.get('a')); + model.get('a').children = []; + await tree.updateChildren(model.root); twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; assert(!hasClass(twistie, 'collapsible')); assert(!hasClass(twistie, 'collapsed')); - assert(tree.getNode(_('a')).collapsed); + assert(tree.getNode(model.get('a')).collapsed); }); test('support default collapse state per element', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; const getChildrenCalls: string[] = []; const dataSource = new class implements IAsyncDataSource { @@ -361,22 +254,139 @@ suite('AsyncDataTree', function () { } }; - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a', children: [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }] }] - }; + }); - const _: (id: string) => Element = find.bind(null, root.children); - - const tree = new AsyncDataTree(container, delegate, [renderer], dataSource, { + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { collapseByDefault: el => el.id !== 'a' }); tree.layout(200); - await tree.setInput(root); - assert(!tree.getNode(_('a')).collapsed); + await tree.setInput(model.root); + assert(!tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root', 'a']); }); -}); \ No newline at end of file + + test('issue #80098 - concurrent refresh and expand', async () => { + const container = document.createElement('div'); + + const calls: Function[] = []; + const dataSource = new class implements IAsyncDataSource { + hasChildren(element: Element): boolean { + return !!element.children && element.children.length > 0; + } + getChildren(element: Element): Promise { + return new Promise(c => calls.push(() => c(element.children))); + } + }; + + const model = new Model({ + id: 'root', + children: [{ + id: 'a', children: [{ + id: 'aa' + }] + }] + }); + + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); + tree.layout(200); + + const pSetInput = tree.setInput(model.root); + calls.pop()!(); // resolve getChildren(root) + await pSetInput; + + const pUpdateChildrenA = tree.updateChildren(model.get('a')); + const pExpandA = tree.expand(model.get('a')); + assert.equal(calls.length, 1, 'expand(a) still hasn\'t called getChildren(a)'); + + calls.pop()!(); + assert.equal(calls.length, 0, 'no pending getChildren calls'); + + await pUpdateChildrenA; + assert.equal(calls.length, 0, 'expand(a) should not have forced a second refresh'); + + const result = await pExpandA; + assert.equal(result, true, 'expand(a) should be done'); + }); + + test('issue #80098 - first expand should call getChildren', async () => { + const container = document.createElement('div'); + + const calls: Function[] = []; + const dataSource = new class implements IAsyncDataSource { + hasChildren(element: Element): boolean { + return !!element.children && element.children.length > 0; + } + getChildren(element: Element): Promise { + return new Promise(c => calls.push(() => c(element.children))); + } + }; + + const model = new Model({ + id: 'root', + children: [{ + id: 'a', children: [{ + id: 'aa' + }] + }] + }); + + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); + tree.layout(200); + + const pSetInput = tree.setInput(model.root); + calls.pop()!(); // resolve getChildren(root) + await pSetInput; + + const pExpandA = tree.expand(model.get('a')); + assert.equal(calls.length, 1, 'expand(a) should\'ve called getChildren(a)'); + + let race = await Promise.race([pExpandA.then(() => 'expand'), timeout(1).then(() => 'timeout')]); + assert.equal(race, 'timeout', 'expand(a) should not be yet done'); + + calls.pop()!(); + assert.equal(calls.length, 0, 'no pending getChildren calls'); + + race = await Promise.race([pExpandA.then(() => 'expand'), timeout(1).then(() => 'timeout')]); + assert.equal(race, 'expand', 'expand(a) should now be done'); + }); + + test('issue #78388 - tree should react to hasChildren toggles', async () => { + const container = document.createElement('div'); + const model = new Model({ + id: 'root', + children: [{ + id: 'a' + }] + }); + + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], new DataSource(), { identityProvider: new IdentityProvider() }); + tree.layout(200); + + await tree.setInput(model.root); + assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); + + let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; + assert(!hasClass(twistie, 'collapsible')); + assert(!hasClass(twistie, 'collapsed')); + + model.get('a').children = [{ id: 'aa' }]; + await tree.updateChildren(model.get('a'), false); + assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); + twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; + assert(hasClass(twistie, 'collapsible')); + assert(hasClass(twistie, 'collapsed')); + + model.get('a').children = []; + await tree.updateChildren(model.get('a'), false); + assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); + twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; + assert(!hasClass(twistie, 'collapsible')); + assert(!hasClass(twistie, 'collapsed')); + }); +}); 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 d1d6c9a68b..9601db91f0 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, CompressedTreeModel } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; +import { compress, ICompressedTreeElement, ICompressedTreeNode, decompress, CompressedObjectTreeModel } 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 CompressedTreeModel(toSpliceable(list)); + const model = new CompressedObjectTreeModel('test', 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 CompressedTreeModel(toSpliceable(list)); + const model = new CompressedObjectTreeModel('test', toSpliceable(list)); model.setChildren(null, Iterator.fromArray([ { element: 0 }, @@ -340,7 +340,7 @@ suite('CompressedObjectTree', function () { test('nested', () => { const list: ITreeNode>[] = []; - const model = new CompressedTreeModel(toSpliceable(list)); + const model = new CompressedObjectTreeModel('test', toSpliceable(list)); model.setChildren(null, Iterator.fromArray([ { @@ -376,7 +376,7 @@ suite('CompressedObjectTree', function () { test('compressed', () => { const list: ITreeNode>[] = []; - const model = new CompressedTreeModel(toSpliceable(list)); + const model = new CompressedObjectTreeModel('test', toSpliceable(list)); model.setChildren(null, Iterator.fromArray([ { @@ -427,4 +427,4 @@ suite('CompressedObjectTree', function () { assert.equal(model.size, 8); }); }); -}); \ No newline at end of file +}); diff --git a/src/vs/base/test/browser/ui/tree/dataTree.test.ts b/src/vs/base/test/browser/ui/tree/dataTree.test.ts index 98b4912d1e..9fc161bc81 100644 --- a/src/vs/base/test/browser/ui/tree/dataTree.test.ts +++ b/src/vs/base/test/browser/ui/tree/dataTree.test.ts @@ -63,7 +63,7 @@ suite('DataTree', function () { } }; - tree = new DataTree(container, delegate, [renderer], dataSource, { + tree = new DataTree('test', container, delegate, [renderer], dataSource, { identityProvider }); tree.layout(200); @@ -145,4 +145,4 @@ suite('DataTree', function () { assert.deepEqual(tree.getSelection(), [root.children![1]]); assert.deepEqual(tree.getFocus(), [root.children![2]]); }); -}); \ No newline at end of file +}); diff --git a/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts b/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts index 34308d3592..347c780ae4 100644 --- a/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts +++ b/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { ITreeNode, ITreeFilter, TreeVisibility } from 'vs/base/browser/ui/tree/tree'; import { ISpliceable } from 'vs/base/common/sequence'; import { Iterator } from 'vs/base/common/iterator'; -import { IndexTreeModel } from 'vs/base/browser/ui/tree/indexTreeModel'; +import { IndexTreeModel, IIndexTreeNode } from 'vs/base/browser/ui/tree/indexTreeModel'; function toSpliceable(arr: T[]): ISpliceable { return { @@ -25,14 +25,14 @@ suite('IndexTreeModel', function () { test('ctor', () => { const list: ITreeNode[] = []; - const model = new IndexTreeModel(toSpliceable(list), -1); + const model = new IndexTreeModel('test', toSpliceable(list), -1); assert(model); assert.equal(list.length, 0); }); test('insert', () => { const list: ITreeNode[] = []; - const model = new IndexTreeModel(toSpliceable(list), -1); + const model = new IndexTreeModel('test', toSpliceable(list), -1); model.splice([0], 0, Iterator.fromArray([ { element: 0 }, @@ -54,7 +54,7 @@ suite('IndexTreeModel', function () { test('deep insert', function () { const list: ITreeNode[] = []; - const model = new IndexTreeModel(toSpliceable(list), -1); + const model = new IndexTreeModel('test', toSpliceable(list), -1); model.splice([0], 0, Iterator.fromArray([ { @@ -91,7 +91,7 @@ suite('IndexTreeModel', function () { test('deep insert collapsed', function () { const list: ITreeNode[] = []; - const model = new IndexTreeModel(toSpliceable(list), -1); + const model = new IndexTreeModel('test', toSpliceable(list), -1); model.splice([0], 0, Iterator.fromArray([ { @@ -119,7 +119,7 @@ suite('IndexTreeModel', function () { test('delete', () => { const list: ITreeNode[] = []; - const model = new IndexTreeModel(toSpliceable(list), -1); + const model = new IndexTreeModel('test', toSpliceable(list), -1); model.splice([0], 0, Iterator.fromArray([ { element: 0 }, @@ -144,7 +144,7 @@ suite('IndexTreeModel', function () { test('nested delete', function () { const list: ITreeNode[] = []; - const model = new IndexTreeModel(toSpliceable(list), -1); + const model = new IndexTreeModel('test', toSpliceable(list), -1); model.splice([0], 0, Iterator.fromArray([ { @@ -178,7 +178,7 @@ suite('IndexTreeModel', function () { test('deep delete', function () { const list: ITreeNode[] = []; - const model = new IndexTreeModel(toSpliceable(list), -1); + const model = new IndexTreeModel('test', toSpliceable(list), -1); model.splice([0], 0, Iterator.fromArray([ { @@ -206,7 +206,7 @@ suite('IndexTreeModel', function () { test('hidden delete', function () { const list: ITreeNode[] = []; - const model = new IndexTreeModel(toSpliceable(list), -1); + const model = new IndexTreeModel('test', toSpliceable(list), -1); model.splice([0], 0, Iterator.fromArray([ { @@ -231,7 +231,7 @@ suite('IndexTreeModel', function () { test('collapse', () => { const list: ITreeNode[] = []; - const model = new IndexTreeModel(toSpliceable(list), -1); + const model = new IndexTreeModel('test', toSpliceable(list), -1); model.splice([0], 0, Iterator.fromArray([ { @@ -262,7 +262,7 @@ suite('IndexTreeModel', function () { test('expand', () => { const list: ITreeNode[] = []; - const model = new IndexTreeModel(toSpliceable(list), -1); + const model = new IndexTreeModel('test', toSpliceable(list), -1); model.splice([0], 0, Iterator.fromArray([ { @@ -302,7 +302,7 @@ suite('IndexTreeModel', function () { test('collapse should recursively adjust visible count', function () { const list: ITreeNode[] = []; - const model = new IndexTreeModel(toSpliceable(list), -1); + const model = new IndexTreeModel('test', toSpliceable(list), -1); model.splice([0], 0, Iterator.fromArray([ { @@ -333,6 +333,67 @@ suite('IndexTreeModel', function () { assert.deepEqual(toArray(list), [1, 11, 2]); }); + test('setCollapsible', () => { + const list: ITreeNode[] = []; + const model = new IndexTreeModel('test', toSpliceable(list), -1); + + model.splice([0], 0, Iterator.fromArray([ + { + element: 0, children: Iterator.fromArray([ + { element: 10 } + ]) + } + ])); + + assert.deepEqual(list.length, 2); + + model.setCollapsible([0], false); + assert.deepEqual(list.length, 2); + assert.deepEqual(list[0].element, 0); + assert.deepEqual(list[0].collapsible, false); + assert.deepEqual(list[0].collapsed, false); + assert.deepEqual(list[1].element, 10); + assert.deepEqual(list[1].collapsible, false); + assert.deepEqual(list[1].collapsed, false); + + model.setCollapsed([0], true); + assert.deepEqual(list.length, 1); + assert.deepEqual(list[0].element, 0); + assert.deepEqual(list[0].collapsible, false); + assert.deepEqual(list[0].collapsed, true); + + model.setCollapsed([0], false); + assert.deepEqual(list[0].element, 0); + assert.deepEqual(list[0].collapsible, false); + assert.deepEqual(list[0].collapsed, false); + assert.deepEqual(list[1].element, 10); + assert.deepEqual(list[1].collapsible, false); + assert.deepEqual(list[1].collapsed, false); + + model.setCollapsible([0], true); + assert.deepEqual(list.length, 2); + assert.deepEqual(list[0].element, 0); + assert.deepEqual(list[0].collapsible, true); + assert.deepEqual(list[0].collapsed, false); + assert.deepEqual(list[1].element, 10); + assert.deepEqual(list[1].collapsible, false); + assert.deepEqual(list[1].collapsed, false); + + model.setCollapsed([0], true); + assert.deepEqual(list.length, 1); + assert.deepEqual(list[0].element, 0); + assert.deepEqual(list[0].collapsible, true); + assert.deepEqual(list[0].collapsed, true); + + model.setCollapsed([0], false); + assert.deepEqual(list[0].element, 0); + assert.deepEqual(list[0].collapsible, true); + assert.deepEqual(list[0].collapsed, false); + assert.deepEqual(list[1].element, 10); + assert.deepEqual(list[1].collapsible, false); + assert.deepEqual(list[1].collapsed, false); + }); + test('simple filter', function () { const list: ITreeNode[] = []; const filter = new class implements ITreeFilter { @@ -341,7 +402,7 @@ suite('IndexTreeModel', function () { } }; - const model = new IndexTreeModel(toSpliceable(list), -1, { filter }); + const model = new IndexTreeModel('test', toSpliceable(list), -1, { filter }); model.splice([0], 0, Iterator.fromArray([ { @@ -375,7 +436,7 @@ suite('IndexTreeModel', function () { } }; - const model = new IndexTreeModel(toSpliceable(list), -1, { filter }); + const model = new IndexTreeModel('test', toSpliceable(list), -1, { filter }); model.splice([0], 0, Iterator.fromArray([ { @@ -398,7 +459,7 @@ suite('IndexTreeModel', function () { } }; - const model = new IndexTreeModel(toSpliceable(list), -1, { filter }); + const model = new IndexTreeModel('test', toSpliceable(list), -1, { filter }); model.splice([0], 0, Iterator.fromArray([ { @@ -437,7 +498,7 @@ suite('IndexTreeModel', function () { } }; - const model = new IndexTreeModel(toSpliceable(list), 'root', { filter }); + const model = new IndexTreeModel('test', toSpliceable(list), 'root', { filter }); model.splice([0], 0, Iterator.fromArray([ { @@ -483,7 +544,7 @@ suite('IndexTreeModel', function () { } }; - const model = new IndexTreeModel(toSpliceable(list), 'root', { filter }); + const model = new IndexTreeModel('test', toSpliceable(list), 'root', { filter }); model.splice([0], 0, Iterator.fromArray([ { @@ -529,7 +590,7 @@ suite('IndexTreeModel', function () { } }; - const model = new IndexTreeModel(toSpliceable(list), 'root', { filter }); + const model = new IndexTreeModel('test', toSpliceable(list), 'root', { filter }); model.splice([0], 0, Iterator.fromArray([ { @@ -576,8 +637,8 @@ suite('IndexTreeModel', function () { suite('getNodeLocation', function () { test('simple', function () { - const list: ITreeNode[] = []; - const model = new IndexTreeModel(toSpliceable(list), -1); + const list: IIndexTreeNode[] = []; + const model = new IndexTreeModel('test', toSpliceable(list), -1); model.splice([0], 0, Iterator.fromArray([ { @@ -600,14 +661,14 @@ suite('IndexTreeModel', function () { }); test('with filter', function () { - const list: ITreeNode[] = []; + const list: IIndexTreeNode[] = []; const filter = new class implements ITreeFilter { filter(element: number): TreeVisibility { return element % 2 === 0 ? TreeVisibility.Visible : TreeVisibility.Hidden; } }; - const model = new IndexTreeModel(toSpliceable(list), -1, { filter }); + const model = new IndexTreeModel('test', toSpliceable(list), -1, { filter }); model.splice([0], 0, Iterator.fromArray([ { @@ -629,4 +690,4 @@ suite('IndexTreeModel', function () { assert.deepEqual(model.getNodeLocation(list[3]), [0, 5]); }); }); -}); \ No newline at end of file +}); diff --git a/src/vs/base/test/browser/ui/tree/objectTree.test.ts b/src/vs/base/test/browser/ui/tree/objectTree.test.ts index 333b4ed4e4..d748307051 100644 --- a/src/vs/base/test/browser/ui/tree/objectTree.test.ts +++ b/src/vs/base/test/browser/ui/tree/objectTree.test.ts @@ -6,8 +6,9 @@ import * as assert from 'assert'; import { ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree'; import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list'; -import { ObjectTree } from 'vs/base/browser/ui/tree/objectTree'; +import { ObjectTree, CompressibleObjectTree, ICompressibleTreeRenderer } from 'vs/base/browser/ui/tree/objectTree'; import { Iterator } from 'vs/base/common/iterator'; +import { ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; suite('ObjectTree', function () { suite('TreeNavigator', function () { @@ -35,7 +36,7 @@ suite('ObjectTree', function () { disposeTemplate(): void { } }; - tree = new ObjectTree(container, delegate, [renderer], { filter: { filter: (el) => filter(el) } }); + tree = new ObjectTree('test', container, delegate, [renderer], { filter: { filter: (el) => filter(el) } }); tree.layout(200); }); @@ -81,8 +82,6 @@ suite('ObjectTree', function () { assert.equal(navigator.previous(), null); assert.equal(navigator.next(), 0); assert.equal(navigator.next(), 10); - assert.equal(navigator.parent(), 0); - assert.equal(navigator.parent(), null); assert.equal(navigator.first(), 0); assert.equal(navigator.last(), 2); }); @@ -112,7 +111,6 @@ suite('ObjectTree', function () { assert.equal(navigator.previous(), 0); assert.equal(navigator.previous(), null); assert.equal(navigator.next(), 0); - assert.equal(navigator.parent(), null); assert.equal(navigator.first(), 0); assert.equal(navigator.last(), 2); }); @@ -147,8 +145,6 @@ suite('ObjectTree', function () { assert.equal(navigator.previous(), null); assert.equal(navigator.next(), 0); assert.equal(navigator.next(), 10); - assert.equal(navigator.parent(), 0); - assert.equal(navigator.parent(), null); assert.equal(navigator.first(), 0); assert.equal(navigator.last(), 2); }); @@ -180,8 +176,6 @@ suite('ObjectTree', function () { assert.equal(navigator.previous(), null); assert.equal(navigator.next(), 0); assert.equal(navigator.next(), 10); - assert.equal(navigator.parent(), 0); - assert.equal(navigator.parent(), null); assert.equal(navigator.first(), 0); assert.equal(navigator.last(), 2); }); @@ -214,7 +208,7 @@ suite('ObjectTree', function () { } }; - const tree = new ObjectTree(container, delegate, [renderer], { identityProvider }); + const tree = new ObjectTree('test', container, delegate, [renderer], { identityProvider }); tree.layout(200); tree.setChildren(null, [{ element: 0 }, { element: 1 }, { element: 2 }, { element: 3 }]); @@ -224,4 +218,161 @@ suite('ObjectTree', function () { tree.setChildren(null, [{ element: 100 }, { element: 101 }, { element: 102 }, { element: 103 }]); assert.deepStrictEqual(tree.getFocus(), [101]); }); -}); \ No newline at end of file +}); + +function toArray(list: NodeList): Node[] { + const result: Node[] = []; + list.forEach(node => result.push(node)); + return result; +} + +suite('CompressibleObjectTree', function () { + + class Delegate implements IListVirtualDelegate { + getHeight() { return 20; } + getTemplateId(): string { return 'default'; } + } + + class Renderer implements ICompressibleTreeRenderer { + readonly templateId = 'default'; + renderTemplate(container: HTMLElement): HTMLElement { + return container; + } + renderElement(node: ITreeNode, _: number, templateData: HTMLElement): void { + templateData.textContent = `${node.element}`; + } + renderCompressedElements(node: ITreeNode, void>, _: number, templateData: HTMLElement): void { + templateData.textContent = `${node.element.elements.join('/')}`; + } + disposeTemplate(): void { } + } + + test('empty', function () { + const container = document.createElement('div'); + container.style.width = '200px'; + container.style.height = '200px'; + + const tree = new CompressibleObjectTree('test', container, new Delegate(), [new Renderer()]); + tree.layout(200); + + const rows = toArray(container.querySelectorAll('.monaco-tl-contents')); + assert.equal(rows.length, 0); + }); + + test('simple', function () { + const container = document.createElement('div'); + container.style.width = '200px'; + container.style.height = '200px'; + + const tree = new CompressibleObjectTree('test', container, new Delegate(), [new Renderer()]); + tree.layout(200); + + tree.setChildren(null, [ + { + element: 0, children: [ + { element: 10 }, + { element: 11 }, + { element: 12 }, + ] + }, + { element: 1 }, + { element: 2 } + ]); + + const rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent); + assert.deepEqual(rows, ['0', '10', '11', '12', '1', '2']); + }); + + test('compressed', () => { + const container = document.createElement('div'); + container.style.width = '200px'; + container.style.height = '200px'; + + const tree = new CompressibleObjectTree('test', container, new Delegate(), [new Renderer()]); + tree.layout(200); + + tree.setChildren(null, Iterator.fromArray([ + { + element: 1, children: Iterator.fromArray([{ + element: 11, children: Iterator.fromArray([{ + element: 111, children: Iterator.fromArray([ + { element: 1111 }, + { element: 1112 }, + { element: 1113 }, + ]) + }]) + }]) + } + ])); + + let rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent); + assert.deepEqual(rows, ['1/11/111', '1111', '1112', '1113']); + + tree.setChildren(11, Iterator.fromArray([ + { element: 111 }, + { element: 112 }, + { element: 113 }, + ])); + + rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent); + assert.deepEqual(rows, ['1/11', '111', '112', '113']); + + tree.setChildren(113, Iterator.fromArray([ + { element: 1131 } + ])); + + rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent); + assert.deepEqual(rows, ['1/11', '111', '112', '113/1131']); + + tree.setChildren(1131, Iterator.fromArray([ + { element: 1132 } + ])); + + rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent); + assert.deepEqual(rows, ['1/11', '111', '112', '113/1131/1132']); + + tree.setChildren(1131, Iterator.fromArray([ + { element: 1132 }, + { element: 1133 }, + ])); + + rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent); + assert.deepEqual(rows, ['1/11', '111', '112', '113/1131', '1132', '1133']); + }); + + test('enableCompression', () => { + const container = document.createElement('div'); + container.style.width = '200px'; + container.style.height = '200px'; + + const tree = new CompressibleObjectTree('test', container, new Delegate(), [new Renderer()]); + tree.layout(200); + + assert.equal(tree.isCompressionEnabled(), true); + + tree.setChildren(null, Iterator.fromArray([ + { + element: 1, children: Iterator.fromArray([{ + element: 11, children: Iterator.fromArray([{ + element: 111, children: Iterator.fromArray([ + { element: 1111 }, + { element: 1112 }, + { element: 1113 }, + ]) + }]) + }]) + } + ])); + + let rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent); + assert.deepEqual(rows, ['1/11/111', '1111', '1112', '1113']); + + tree.setCompressionEnabled(false); + rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent); + assert.deepEqual(rows, ['1', '11', '111', '1111', '1112', '1113']); + + tree.setCompressionEnabled(true); + rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent); + assert.deepEqual(rows, ['1/11/111', '1111', '1112', '1113']); + }); +}); diff --git a/src/vs/base/test/browser/ui/tree/objectTreeModel.test.ts b/src/vs/base/test/browser/ui/tree/objectTreeModel.test.ts index 79694d62fe..f1fc8c4166 100644 --- a/src/vs/base/test/browser/ui/tree/objectTreeModel.test.ts +++ b/src/vs/base/test/browser/ui/tree/objectTreeModel.test.ts @@ -25,7 +25,7 @@ suite('ObjectTreeModel', function () { test('ctor', () => { const list: ITreeNode[] = []; - const model = new ObjectTreeModel(toSpliceable(list)); + const model = new ObjectTreeModel('test', toSpliceable(list)); assert(model); assert.equal(list.length, 0); assert.equal(model.size, 0); @@ -33,7 +33,7 @@ suite('ObjectTreeModel', function () { test('flat', () => { const list: ITreeNode[] = []; - const model = new ObjectTreeModel(toSpliceable(list)); + const model = new ObjectTreeModel('test', toSpliceable(list)); model.setChildren(null, Iterator.fromArray([ { element: 0 }, @@ -60,7 +60,7 @@ suite('ObjectTreeModel', function () { test('nested', () => { const list: ITreeNode[] = []; - const model = new ObjectTreeModel(toSpliceable(list)); + const model = new ObjectTreeModel('test', toSpliceable(list)); model.setChildren(null, Iterator.fromArray([ { @@ -96,7 +96,7 @@ suite('ObjectTreeModel', function () { test('setChildren on collapsed node', () => { const list: ITreeNode[] = []; - const model = new ObjectTreeModel(toSpliceable(list)); + const model = new ObjectTreeModel('test', toSpliceable(list)); model.setChildren(null, Iterator.fromArray([ { element: 0, collapsed: true } @@ -117,7 +117,7 @@ suite('ObjectTreeModel', function () { test('setChildren on expanded, unrevealed node', () => { const list: ITreeNode[] = []; - const model = new ObjectTreeModel(toSpliceable(list)); + const model = new ObjectTreeModel('test', toSpliceable(list)); model.setChildren(null, [ { @@ -143,7 +143,7 @@ suite('ObjectTreeModel', function () { test('collapse state is preserved with strict identity', () => { const list: ITreeNode[] = []; - const model = new ObjectTreeModel(toSpliceable(list), { collapseByDefault: true }); + const model = new ObjectTreeModel('test', toSpliceable(list), { collapseByDefault: true }); const data = [{ element: 'father', children: [{ element: 'child' }] }]; model.setChildren(null, data); @@ -173,7 +173,7 @@ suite('ObjectTreeModel', function () { let compare: (a: string, b: string) => number = (a, b) => a < b ? -1 : 1; const list: ITreeNode[] = []; - const model = new ObjectTreeModel(toSpliceable(list), { sorter: { compare(a, b) { return compare(a, b); } } }); + const model = new ObjectTreeModel('test', toSpliceable(list), { sorter: { compare(a, b) { return compare(a, b); } } }); const data = [ { element: 'cars', children: [{ element: 'sedan' }, { element: 'convertible' }, { element: 'compact' }] }, { element: 'airplanes', children: [{ element: 'passenger' }, { element: 'jet' }] }, @@ -188,7 +188,7 @@ suite('ObjectTreeModel', function () { let compare: (a: string, b: string) => number = () => 0; const list: ITreeNode[] = []; - const model = new ObjectTreeModel(toSpliceable(list), { sorter: { compare(a, b) { return compare(a, b); } } }); + const model = new ObjectTreeModel('test', toSpliceable(list), { sorter: { compare(a, b) { return compare(a, b); } } }); const data = [ { element: 'cars', children: [{ element: 'sedan' }, { element: 'convertible' }, { element: 'compact' }] }, { element: 'airplanes', children: [{ element: 'passenger' }, { element: 'jet' }] }, @@ -223,7 +223,7 @@ suite('ObjectTreeModel', function () { test('expandTo', () => { const list: ITreeNode[] = []; - const model = new ObjectTreeModel(toSpliceable(list), { collapseByDefault: true }); + const model = new ObjectTreeModel('test', toSpliceable(list), { collapseByDefault: true }); model.setChildren(null, [ { @@ -241,4 +241,4 @@ suite('ObjectTreeModel', function () { model.expandTo(1000); assert.deepEqual(toArray(list), [0, 10, 100, 1000, 11, 12, 1, 2]); }); -}); \ No newline at end of file +}); diff --git a/src/vs/base/test/common/filters.test.ts b/src/vs/base/test/common/filters.test.ts index d149f09865..dbd841b1d7 100644 --- a/src/vs/base/test/common/filters.test.ts +++ b/src/vs/base/test/common/filters.test.ts @@ -392,6 +392,10 @@ suite('Filters', () => { test('patternPos isn\'t working correctly #79815', function () { assertMatches(':p'.substr(1), 'prop', '^prop', fuzzyScore, { patternPos: 0 }); assertMatches(':p', 'prop', '^prop', fuzzyScore, { patternPos: 1 }); + assertMatches(':p', 'prop', undefined, fuzzyScore, { patternPos: 2 }); + assertMatches(':p', 'proP', 'pro^P', fuzzyScore, { patternPos: 1, wordPos: 1 }); + assertMatches(':p', 'aprop', 'a^prop', fuzzyScore, { patternPos: 1, firstMatchCanBeWeak: true }); + assertMatches(':p', 'aprop', undefined, fuzzyScore, { patternPos: 1, firstMatchCanBeWeak: false }); }); function assertTopScore(filter: typeof fuzzyScore, pattern: string, expected: number, ...words: string[]) { diff --git a/src/vs/base/test/node/glob.test.ts b/src/vs/base/test/node/glob.test.ts index 6e951010dc..33111c9c14 100644 --- a/src/vs/base/test/node/glob.test.ts +++ b/src/vs/base/test/node/glob.test.ts @@ -812,10 +812,10 @@ suite('Glob', () => { '{**/bar/**,**/baz/**}': true, '**/bulb/**': false }, ['foo', 'bar', 'baz'], [ - ['bar/foo', '**/foo/**'], - ['foo/bar', '{**/bar/**,**/baz/**}'], - ['bar/nope', null!] - ]); + ['bar/foo', '**/foo/**'], + ['foo/bar', '{**/bar/**,**/baz/**}'], + ['bar/nope', null!] + ]); const siblings = ['baz', 'baz.zip', 'nope']; const hasSibling = (name: string) => siblings.indexOf(name) !== -1; @@ -823,15 +823,15 @@ suite('Glob', () => { '**/foo/**': { when: '$(basename).zip' }, '**/bar/**': true }, ['bar'], [ - ['bar/foo', null!], - ['bar/foo/baz', null!], - ['bar/foo/nope', null!], - ['foo/bar', '**/bar/**'], - ], [ - null!, - hasSibling, - hasSibling - ]); + ['bar/foo', null!], + ['bar/foo/baz', null!], + ['bar/foo/nope', null!], + ['foo/bar', '**/bar/**'], + ], [ + null!, + hasSibling, + hasSibling + ]); }); function testOptimizationForBasenames(pattern: string | glob.IExpression, basenameTerms: string[], matches: [string, string | boolean][], siblingsFns: ((name: string) => boolean)[] = []) { @@ -917,11 +917,11 @@ suite('Glob', () => { // '{**/bar/bar/**,**/baz/bar/**}': true, '**/bulb/bar/**': false }, ['*/foo/bar'], [ - [nativeSep('bar/foo/bar'), '**/foo/bar/**'], - // Not supported - // [nativeSep('foo/bar/bar'), '{**/bar/bar/**,**/baz/bar/**}'], - [nativeSep('/foo/bar/nope'), null!] - ]); + [nativeSep('bar/foo/bar'), '**/foo/bar/**'], + // Not supported + // [nativeSep('foo/bar/bar'), '{**/bar/bar/**,**/baz/bar/**}'], + [nativeSep('/foo/bar/nope'), null!] + ]); const siblings = ['baz', 'baz.zip', 'nope']; let hasSibling = (name: string) => siblings.indexOf(name) !== -1; @@ -929,15 +929,15 @@ suite('Glob', () => { '**/foo/123/**': { when: '$(basename).zip' }, '**/bar/123/**': true }, ['*/bar/123'], [ - [nativeSep('bar/foo/123'), null!], - [nativeSep('bar/foo/123/baz'), null!], - [nativeSep('bar/foo/123/nope'), null!], - [nativeSep('foo/bar/123'), '**/bar/123/**'], - ], [ - null!, - hasSibling, - hasSibling - ]); + [nativeSep('bar/foo/123'), null!], + [nativeSep('bar/foo/123/baz'), null!], + [nativeSep('bar/foo/123/nope'), null!], + [nativeSep('foo/bar/123'), '**/bar/123/**'], + ], [ + null!, + hasSibling, + hasSibling + ]); }); function testOptimizationForPaths(pattern: string | glob.IExpression, pathTerms: string[], matches: [string, string | boolean][], siblingsFns: ((name: string) => boolean)[] = []) { diff --git a/src/vs/base/test/node/keytar.test.ts b/src/vs/base/test/node/keytar.test.ts index 1dd5ca3a33..329ec334e9 100644 --- a/src/vs/base/test/node/keytar.test.ts +++ b/src/vs/base/test/node/keytar.test.ts @@ -18,6 +18,8 @@ suite('Keytar', () => { const name = `VSCode Test ${Math.floor(Math.random() * 1e9)}`; try { await keytar.setPassword(name, 'foo', 'bar'); + assert.equal(await keytar.findPassword(name), 'bar'); + assert.equal((await keytar.findCredentials(name)).length, 1); assert.equal(await keytar.getPassword(name, 'foo'), 'bar'); await keytar.deletePassword(name, 'foo'); assert.equal(await keytar.getPassword(name, 'foo'), undefined); diff --git a/src/vs/base/worker/workerMain.ts b/src/vs/base/worker/workerMain.ts index b0769949ba..db3a7829ca 100644 --- a/src/vs/base/worker/workerMain.ts +++ b/src/vs/base/worker/workerMain.ts @@ -24,7 +24,7 @@ (self).postMessage(msg, transfer); }, null); - self.onmessage = (e) => messageHandler.onmessage(e.data); + self.onmessage = (e: MessageEvent) => messageHandler.onmessage(e.data); while (beforeReadyMessages.length > 0) { self.onmessage(beforeReadyMessages.shift()!); } @@ -34,7 +34,7 @@ let isFirstMessage = true; let beforeReadyMessages: MessageEvent[] = []; - self.onmessage = (message) => { + self.onmessage = (message: MessageEvent) => { if (!isFirstMessage) { beforeReadyMessages.push(message); return; diff --git a/src/vs/code/browser/workbench/callback.html b/src/vs/code/browser/workbench/callback.html new file mode 100644 index 0000000000..da6c907b66 --- /dev/null +++ b/src/vs/code/browser/workbench/callback.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + + Visual Studio Code + + + + + + + Visual Studio Code + +
+
+ You can close this page now. +
+
+ + diff --git a/src/vs/code/browser/workbench/workbench-dev.html b/src/vs/code/browser/workbench/workbench-dev.html new file mode 100644 index 0000000000..9fb0fab5a1 --- /dev/null +++ b/src/vs/code/browser/workbench/workbench-dev.html @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vs/code/browser/workbench/workbench.html b/src/vs/code/browser/workbench/workbench.html index 44f67f0a0b..97d78ce7f9 100644 --- a/src/vs/code/browser/workbench/workbench.html +++ b/src/vs/code/browser/workbench/workbench.html @@ -10,8 +10,19 @@ + content=" + default-src 'self'; + img-src 'self' https: data: blob:; + media-src 'none'; + script-src 'self' https://az416426.vo.msecnd.net 'unsafe-eval' https: 'sha256-4DqvCTjCHj2KW4QxC/Yt6uBwMRyYiEg7kOoykSEkonQ='; + child-src 'self'; + frame-src 'self' https://*.vscode-webview-test.com; + worker-src 'self'; + style-src 'self' 'unsafe-inline'; + connect-src 'self' ws: wss: https:; + font-src 'self' blob:; + manifest-src 'self'; + "> @@ -23,13 +34,33 @@ + + + + + + diff --git a/src/vs/code/browser/workbench/workbench.js b/src/vs/code/browser/workbench/workbench.js deleted file mode 100644 index 9df7efece4..0000000000 --- a/src/vs/code/browser/workbench/workbench.js +++ /dev/null @@ -1,32 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -//@ts-check -'use strict'; - -(function () { - - /** @type any */ - const amdLoader = require; - - amdLoader.config({ - baseUrl: `${window.location.origin}/static/out`, - paths: { - 'vscode-textmate': `${window.location.origin}/static/node_modules/vscode-textmate/release/main`, - 'onigasm-umd': `${window.location.origin}/static/node_modules/onigasm-umd/release/main`, - 'xterm': `${window.location.origin}/static/node_modules/xterm/lib/xterm.js`, - 'xterm-addon-search': `${window.location.origin}/static/node_modules/xterm-addon-search/lib/xterm-addon-search.js`, - 'xterm-addon-web-links': `${window.location.origin}/static/node_modules/xterm-addon-web-links/lib/xterm-addon-web-links.js`, - 'semver-umd': `${window.location.origin}/static/node_modules/semver-umd/lib/semver-umd.js`, - '@microsoft/applicationinsights-web': `${window.location.origin}/static/node_modules/@microsoft/applicationinsights-web/dist/applicationinsights-web.js`, - } - }); - - amdLoader(['vs/workbench/workbench.web.api'], function (api) { - const options = JSON.parse(document.getElementById('vscode-workbench-web-configuration').getAttribute('data-settings')); - - api.create(document.body, options); - }); -})(); diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts new file mode 100644 index 0000000000..41fc2d055c --- /dev/null +++ b/src/vs/code/browser/workbench/workbench.ts @@ -0,0 +1,208 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IWorkbenchConstructionOptions, create } from 'vs/workbench/workbench.web.api'; +import { IURLCallbackProvider } from 'vs/workbench/services/url/browser/urlService'; +import { Event, Emitter } from 'vs/base/common/event'; +import { URI, UriComponents } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { streamToBuffer } from 'vs/base/common/buffer'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { request } from 'vs/base/parts/request/browser/request'; +import { ICredentialsProvider } from 'vs/workbench/services/credentials/browser/credentialsService'; + +interface ICredential { + service: string; + account: string; + password: string; +} + +class LocalStorageCredentialsProvider implements ICredentialsProvider { + + static readonly CREDENTIALS_OPENED_KEY = 'credentials.provider'; + + private _credentials: ICredential[]; + private get credentials(): ICredential[] { + if (!this._credentials) { + try { + const serializedCredentials = window.localStorage.getItem(LocalStorageCredentialsProvider.CREDENTIALS_OPENED_KEY); + if (serializedCredentials) { + this._credentials = JSON.parse(serializedCredentials); + } + } catch (error) { + // ignore + } + + if (!Array.isArray(this._credentials)) { + this._credentials = []; + } + } + + return this._credentials; + } + + private save(): void { + window.localStorage.setItem(LocalStorageCredentialsProvider.CREDENTIALS_OPENED_KEY, JSON.stringify(this.credentials)); + } + + async getPassword(service: string, account: string): Promise { + return this.doGetPassword(service, account); + } + + private async doGetPassword(service: string, account?: string): Promise { + for (const credential of this.credentials) { + if (credential.service === service) { + if (typeof account !== 'string' || account === credential.account) { + return credential.password; + } + } + } + + return null; + } + + async setPassword(service: string, account: string, password: string): Promise { + this.deletePassword(service, account); + + this.credentials.push({ service, account, password }); + + this.save(); + } + + async deletePassword(service: string, account: string): Promise { + let found = false; + + this._credentials = this.credentials.filter(credential => { + if (credential.service === service && credential.account === account) { + found = true; + + return false; + } + + return true; + }); + + if (found) { + this.save(); + } + + return found; + } + + async findPassword(service: string): Promise { + return this.doGetPassword(service); + } + + async findCredentials(service: string): Promise> { + return this.credentials + .filter(credential => credential.service === service) + .map(({ account, password }) => ({ account, password })); + } +} + +class PollingURLCallbackProvider extends Disposable implements IURLCallbackProvider { + + static FETCH_INTERVAL = 500; // fetch every 500ms + static FETCH_TIMEOUT = 5 * 60 * 1000; // ...but stop after 5min + + static QUERY_KEYS = { + REQUEST_ID: 'vscode-requestId', + SCHEME: 'vscode-scheme', + AUTHORITY: 'vscode-authority', + PATH: 'vscode-path', + QUERY: 'vscode-query', + FRAGMENT: 'vscode-fragment' + }; + + private readonly _onCallback: Emitter = this._register(new Emitter()); + readonly onCallback: Event = this._onCallback.event; + + create(options?: Partial): URI { + const queryValues: Map = new Map(); + + const requestId = generateUuid(); + queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.REQUEST_ID, requestId); + + const { scheme, authority, path, query, fragment } = options ? options : { scheme: undefined, authority: undefined, path: undefined, query: undefined, fragment: undefined }; + + if (scheme) { + queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.SCHEME, scheme); + } + + if (authority) { + queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.AUTHORITY, authority); + } + + if (path) { + queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.PATH, path); + } + + if (query) { + queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.QUERY, query); + } + + if (fragment) { + queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.FRAGMENT, fragment); + } + + // Start to poll on the callback being fired + this.periodicFetchCallback(requestId, Date.now()); + + return this.doCreateUri('/callback', queryValues); + } + + private async periodicFetchCallback(requestId: string, startTime: number): Promise { + + // Ask server for callback results + const queryValues: Map = new Map(); + queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.REQUEST_ID, requestId); + + const result = await request({ + url: this.doCreateUri('/fetch-callback', queryValues).toString(true) + }, CancellationToken.None); + + // Check for callback results + const content = await streamToBuffer(result.stream); + if (content.byteLength > 0) { + try { + this._onCallback.fire(URI.revive(JSON.parse(content.toString()))); + } catch (error) { + console.error(error); + } + + return; // done + } + + // Continue fetching unless we hit the timeout + if (Date.now() - startTime < PollingURLCallbackProvider.FETCH_TIMEOUT) { + setTimeout(() => this.periodicFetchCallback(requestId, startTime), PollingURLCallbackProvider.FETCH_INTERVAL); + } + } + + private doCreateUri(path: string, queryValues: Map): URI { + let query: string | undefined = undefined; + + if (queryValues) { + let index = 0; + queryValues.forEach((value, key) => { + if (!query) { + query = ''; + } + + const prefix = (index++ === 0) ? '' : '&'; + query += `${prefix}${key}=${encodeURIComponent(value)}`; + }); + } + + return URI.parse(window.location.href).with({ path, query }); + } +} + +const options: IWorkbenchConstructionOptions = JSON.parse(document.getElementById('vscode-workbench-web-configuration')!.getAttribute('data-settings')!); +options.urlCallbackProvider = new PollingURLCallbackProvider(); +options.credentialsProvider = new LocalStorageCredentialsProvider(); + +create(document.body, options); diff --git a/src/vs/code/electron-browser/issue/issueReporterMain.ts b/src/vs/code/electron-browser/issue/issueReporterMain.ts index b7a502c738..1f9b21d0aa 100644 --- a/src/vs/code/electron-browser/issue/issueReporterMain.ts +++ b/src/vs/code/electron-browser/issue/issueReporterMain.ts @@ -311,7 +311,7 @@ export class IssueReporter extends Disposable { if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) { const channel = getDelayedChannel(sharedProcess.then(c => c.getChannel('telemetryAppender'))); const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(logService)); - const commonProperties = resolveCommonProperties(product.commit || 'Commit unknown', pkg.version, configuration.machineId, this.environmentService.installSourcePath); + const commonProperties = resolveCommonProperties(product.commit || 'Commit unknown', pkg.version, configuration.machineId, product.msftInternalDomains, this.environmentService.installSourcePath); const piiPaths = this.environmentService.extensionsPath ? [this.environmentService.appRoot, this.environmentService.extensionsPath] : [this.environmentService.appRoot]; const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths }; @@ -941,8 +941,7 @@ export class IssueReporter extends Disposable { } } - // {{SQL CARBON EDIT}} - const queryStringPrefix = repositoryUrl.indexOf('?') === -1 ? '?' : '&'; + const queryStringPrefix = product.reportIssueUrl && product.reportIssueUrl.indexOf('?') === -1 ? '?' : '&'; return `${repositoryUrl}${queryStringPrefix}title=${encodeURIComponent(issueTitle)}`; } diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index d863292909..001458bd16 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -27,7 +27,7 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProper import { TelemetryAppenderChannel } from 'vs/platform/telemetry/node/telemetryIpc'; import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; -import { IWindowsService, ActiveWindowManager } from 'vs/platform/windows/common/windows'; +import { IWindowsService } from 'vs/platform/windows/common/windows'; import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService'; import { ipcRenderer } from 'electron'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; @@ -35,8 +35,6 @@ import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log import { LocalizationsService } from 'vs/platform/localizations/node/localizations'; import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; 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, toDisposable } from 'vs/base/common/lifecycle'; import { DownloadService } from 'vs/platform/download/common/downloadService'; import { IDownloadService } from 'vs/platform/download/common/download'; @@ -46,7 +44,6 @@ import { LanguagePackCachedDataCleaner } from 'vs/code/electron-browser/sharedPr import { StorageDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner'; import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { SpdLogService } from 'vs/platform/log/node/spdlogService'; import { DiagnosticsService, IDiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService'; import { DiagnosticsChannel } from 'vs/platform/diagnostics/node/diagnosticsIpc'; @@ -75,7 +72,7 @@ const eventPrefix = product.quality !== 'stable' ? 'adsworkbench' : 'monacoworkb class MainProcessService implements IMainProcessService { constructor(private server: Server, private mainRouter: StaticRouter) { } - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; getChannel(channelName: string): IChannel { return this.server.getChannel(channelName, this.mainRouter); @@ -121,11 +118,6 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat const windowsService = new WindowsService(mainProcessService); services.set(IWindowsService, windowsService); - const activeWindowManager = new ActiveWindowManager(windowsService); - const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id)); - const dialogChannel = server.getChannel('dialog', activeWindowRouter); - services.set(IDialogService, new DialogChannelClient(dialogChannel)); - // Files const fileService = new FileService(logService); services.set(IFileService, fileService); @@ -156,7 +148,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat } const config: ITelemetryServiceConfig = { appender: combinedAppender(appInsightsAppender, new LogAppender(logService)), - commonProperties: resolveCommonProperties(product.commit, pkg.version, configuration.machineId, installSourcePath), + commonProperties: resolveCommonProperties(product.commit, pkg.version, configuration.machineId, product.msftInternalDomains, installSourcePath), piiPaths: extensionsPath ? [appRoot, extensionsPath] : [appRoot] }; diff --git a/src/vs/code/electron-browser/workbench/workbench.js b/src/vs/code/electron-browser/workbench/workbench.js index 27782ac0e6..e275ba1b6d 100644 --- a/src/vs/code/electron-browser/workbench/workbench.js +++ b/src/vs/code/electron-browser/workbench/workbench.js @@ -49,7 +49,7 @@ bootstrapWindow.load([ * @param {{ * partsSplashPath?: string, * highContrast?: boolean, - * extensionDevelopmentPath?: string | string[], + * extensionDevelopmentPath?: string[], * folderUri?: object, * workspace?: object * }} configuration diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 091c63054f..7ae330744c 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -12,7 +12,7 @@ import { WindowsService } from 'vs/platform/windows/electron-main/windowsService import { ILifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; import { getShellEnvironment } from 'vs/code/node/shellEnv'; import { IUpdateService } from 'vs/platform/update/common/update'; -import { UpdateChannel } from 'vs/platform/update/node/updateIpc'; +import { UpdateChannel } from 'vs/platform/update/electron-main/updateIpc'; import { Server as ElectronIPCServer } from 'vs/base/parts/ipc/electron-main/ipc.electron-main'; import { Client } from 'vs/base/parts/ipc/common/ipc.net'; import { Server, connect } from 'vs/base/parts/ipc/node/ipc.net'; @@ -26,7 +26,7 @@ import { IStateService } from 'vs/platform/state/common/state'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IURLService } from 'vs/platform/url/common/url'; -import { URLHandlerChannelClient, URLServiceChannel } from 'vs/platform/url/node/urlIpc'; +import { URLHandlerChannelClient, URLServiceChannel, URLHandlerRouter } from 'vs/platform/url/common/urlIpc'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService, combinedAppender, LogAppender } from 'vs/platform/telemetry/common/telemetryUtils'; import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc'; @@ -56,7 +56,6 @@ import { serve as serveDriver } from 'vs/platform/driver/electron-main/driver'; import { IMenubarService } from 'vs/platform/menubar/node/menubar'; import { MenubarService } from 'vs/platform/menubar/electron-main/menubarService'; import { MenubarChannel } from 'vs/platform/menubar/node/menubarIpc'; -import { hasArgs } from 'vs/platform/environment/node/argv'; import { RunOnceScheduler } from 'vs/base/common/async'; import { registerContextMenuListener } from 'vs/base/parts/contextmenu/electron-main/contextmenu'; import { homedir } from 'os'; @@ -332,8 +331,9 @@ export class CodeApplication extends Disposable { // This will help Windows to associate the running program with // any shortcut that is pinned to the taskbar and prevent showing // two icons in the taskbar for the same app. - if (isWindows && product.win32AppUserModelId) { - app.setAppUserModelId(product.win32AppUserModelId); + const win32AppUserModelId = product.win32AppUserModelId; + if (isWindows && win32AppUserModelId) { + app.setAppUserModelId(win32AppUserModelId); } // Fix native tabs on macOS 10.13 @@ -474,7 +474,7 @@ export class CodeApplication extends Disposable { if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) { const channel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('telemetryAppender'))); const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService)); - const commonProperties = resolveCommonProperties(product.commit, pkg.version, machineId, this.environmentService.installSourcePath); + const commonProperties = resolveCommonProperties(product.commit, pkg.version, machineId, product.msftInternalDomains, this.environmentService.installSourcePath); const piiPaths = this.environmentService.extensionsPath ? [this.environmentService.appRoot, this.environmentService.extensionsPath] : [this.environmentService.appRoot]; const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths, trueMachineId }; @@ -580,7 +580,8 @@ export class CodeApplication extends Disposable { // Create a URL handler which forwards to the last active window const activeWindowManager = new ActiveWindowManager(windowsService); const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id)); - const urlHandlerChannel = electronIpcServer.getChannel('urlHandler', activeWindowRouter); + const urlHandlerRouter = new URLHandlerRouter(activeWindowRouter); + const urlHandlerChannel = electronIpcServer.getChannel('urlHandler', urlHandlerRouter); const multiplexURLHandler = new URLHandlerChannelClient(urlHandlerChannel); // On Mac, Code can be running without any open windows, so we must create a window to handle urls, @@ -616,9 +617,9 @@ export class CodeApplication extends Disposable { // Open our first window const macOpenFiles: string[] = (global).macOpenFiles; const context = !!process.env['VSCODE_CLI'] ? OpenContext.CLI : OpenContext.DESKTOP; - const hasCliArgs = hasArgs(args._); - const hasFolderURIs = hasArgs(args['folder-uri']); - const hasFileURIs = hasArgs(args['file-uri']); + const hasCliArgs = args._.length; + const hasFolderURIs = !!args['folder-uri']; + const hasFileURIs = !!args['file-uri']; const noRecentEntry = args['skip-add-to-recently-opened'] === true; const waitMarkerFileURI = args.wait && args.waitMarkerFilePath ? URI.file(args.waitMarkerFilePath) : undefined; diff --git a/src/vs/code/electron-main/auth.ts b/src/vs/code/electron-main/auth.ts index 214e9a7e15..57bb78578e 100644 --- a/src/vs/code/electron-main/auth.ts +++ b/src/vs/code/electron-main/auth.ts @@ -24,7 +24,7 @@ type Credentials = { export class ProxyAuthHandler { - _serviceBrand: any; + _serviceBrand: undefined; private retryCount = 0; private disposables: IDisposable[] = []; diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index c39a115f8d..06549d2ce1 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/platform/update/node/update.config.contribution'; +import 'vs/platform/update/common/update.config.contribution'; import { app, dialog } from 'electron'; import { assign } from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 61d4020a37..67cfad1759 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -11,7 +11,7 @@ import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, R import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import product from 'vs/platform/product/node/product'; import { IWindowSettings, MenuBarVisibility, IWindowConfiguration, ReadyState, getTitleBarStyle } from 'vs/platform/windows/common/windows'; import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -32,7 +32,7 @@ const RUN_TEXTMATE_IN_WORKER = false; export interface IWindowCreationOptions { state: IWindowState; - extensionDevelopmentPath?: string | string[]; + extensionDevelopmentPath?: string[]; isExtensionTestHost?: boolean; } @@ -574,7 +574,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { windowConfiguration.partsSplashPath = path.join(this.environmentService.userDataPath, 'rapid_render.json'); // Config (combination of process.argv and window configuration) - const environment = parseArgs(process.argv); + const environment = parseArgs(process.argv, OPTIONS); const config = objects.assign(environment, windowConfiguration); for (const key in config) { const configValue = (config as any)[key]; diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index d2f0b32de6..637ced15d8 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -12,7 +12,6 @@ import { IBackupMainService, IEmptyWindowBackupInfo } from 'vs/platform/backup/c import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { IStateService } from 'vs/platform/state/common/state'; import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window'; -import { hasArgs, asArray } from 'vs/platform/environment/node/argv'; import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter } from 'electron'; import { parseLineAndColumnAware } from 'vs/code/node/paths'; import { ILifecycleService, UnloadReason, LifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; @@ -157,7 +156,7 @@ interface IWorkspacePathToOpen { export class WindowsManager extends Disposable implements IWindowsMainService { - _serviceBrand: any; + _serviceBrand: undefined; private static readonly windowsStateStorageKey = 'windowsState'; @@ -211,10 +210,11 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } private installWindowsMutex(): void { - if (isWindows) { + const win32MutexName = product.win32MutexName; + if (isWindows && win32MutexName) { try { const WindowsMutex = (require.__$__nodeRequire('windows-mutex') as typeof import('windows-mutex')).Mutex; - const mutex = new WindowsMutex(product.win32MutexName); + const mutex = new WindowsMutex(win32MutexName); once(this.lifecycleService.onWillShutdown)(() => mutex.release()); } catch (e) { this.logService.error(e); @@ -309,7 +309,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { if (!currentWindowsState.lastActiveWindow) { let activeWindow = this.getLastActiveWindow(); if (!activeWindow || activeWindow.isExtensionDevelopmentHost) { - activeWindow = WindowsManager.WINDOWS.filter(w => !w.isExtensionDevelopmentHost)[0]; + activeWindow = WindowsManager.WINDOWS.filter(window => !window.isExtensionDevelopmentHost)[0]; } if (activeWindow) { @@ -318,7 +318,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } // 2.) Find extension host window - const extensionHostWindow = WindowsManager.WINDOWS.filter(w => w.isExtensionDevelopmentHost && !w.isExtensionTestHost)[0]; + const extensionHostWindow = WindowsManager.WINDOWS.filter(window => window.isExtensionDevelopmentHost && !window.isExtensionTestHost)[0]; if (extensionHostWindow) { currentWindowsState.lastPluginDevelopmentHostWindow = this.toWindowState(extensionHostWindow); } @@ -329,7 +329,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // so if we ever want to persist the UI state of the last closed window (window count === 1), it has // to come from the stored lastClosedWindowState on Win/Linux at least if (this.getWindowCount() > 1) { - currentWindowsState.openedWindows = WindowsManager.WINDOWS.filter(w => !w.isExtensionDevelopmentHost).map(w => this.toWindowState(w)); + currentWindowsState.openedWindows = WindowsManager.WINDOWS.filter(window => !window.isExtensionDevelopmentHost).map(window => this.toWindowState(window)); } // Persist @@ -450,13 +450,13 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // Make sure to pass focus to the most relevant of the windows if we open multiple if (usedWindows.length > 1) { - const focusLastActive = this.windowsState.lastActiveWindow && !openConfig.forceEmpty && !hasArgs(openConfig.cli._) && !hasArgs(openConfig.cli['file-uri']) && !hasArgs(openConfig.cli['folder-uri']) && !(openConfig.urisToOpen && openConfig.urisToOpen.length); + const focusLastActive = this.windowsState.lastActiveWindow && !openConfig.forceEmpty && openConfig.cli._.length && !openConfig.cli['file-uri'] && !openConfig.cli['folder-uri'] && !(openConfig.urisToOpen && openConfig.urisToOpen.length); let focusLastOpened = true; let focusLastWindow = true; // 1.) focus last active window if we are not instructed to open any paths if (focusLastActive) { - const lastActiveWindow = usedWindows.filter(w => w.backupPath === this.windowsState.lastActiveWindow!.backupPath); + const lastActiveWindow = usedWindows.filter(window => window.backupPath === this.windowsState.lastActiveWindow!.backupPath); if (lastActiveWindow.length) { lastActiveWindow[0].focus(); focusLastOpened = false; @@ -490,7 +490,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // Remember in recent document list (unless this opens for extension development) // Also do not add paths when files are opened for diffing, only if opened individually - if (!usedWindows.some(w => w.isExtensionDevelopmentHost) && !openConfig.diffMode && !openConfig.noRecentEntry) { + if (!usedWindows.some(window => window.isExtensionDevelopmentHost) && !openConfig.diffMode && !openConfig.noRecentEntry) { const recents: IRecent[] = []; for (let pathToOpen of pathsToOpen) { if (pathToOpen.workspace) { @@ -556,7 +556,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { const fileToCheck = fileInputs.filesToOpenOrCreate[0] || fileInputs.filesToDiff[0]; // only look at the windows with correct authority - const windows = WindowsManager.WINDOWS.filter(w => w.remoteAuthority === fileInputs!.remoteAuthority); + const windows = WindowsManager.WINDOWS.filter(window => window.remoteAuthority === fileInputs!.remoteAuthority); const bestWindowOrFolder = findBestWindowOrFolderForFile({ windows, @@ -811,7 +811,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } // Extract paths: from CLI - else if (hasArgs(openConfig.cli._) || hasArgs(openConfig.cli['folder-uri']) || hasArgs(openConfig.cli['file-uri'])) { + else if (openConfig.cli._.length || openConfig.cli['folder-uri'] || openConfig.cli['file-uri']) { windowsToOpen = this.doExtractPathsFromCLI(openConfig.cli); isCommandLineOrAPICall = true; } @@ -885,31 +885,36 @@ export class WindowsManager extends Disposable implements IWindowsMainService { const parseOptions: IPathParseOptions = { ignoreFileNotFound: true, gotoLineMode: cli.goto, remoteAuthority: cli.remote || undefined }; // folder uris - const folderUris = asArray(cli['folder-uri']); - for (let f of folderUris) { - const folderUri = this.argToUri(f); - if (folderUri) { - const path = this.parseUri({ folderUri }, parseOptions); - if (path) { - pathsToOpen.push(path); + const folderUris = cli['folder-uri']; + if (folderUris) { + for (let f of folderUris) { + const folderUri = this.argToUri(f); + if (folderUri) { + const path = this.parseUri({ folderUri }, parseOptions); + if (path) { + pathsToOpen.push(path); + } } } } + // file uris - const fileUris = asArray(cli['file-uri']); - for (let f of fileUris) { - const fileUri = this.argToUri(f); - if (fileUri) { - const path = this.parseUri(hasWorkspaceFileExtension(f) ? { workspaceUri: fileUri } : { fileUri }, parseOptions); - if (path) { - pathsToOpen.push(path); + const fileUris = cli['file-uri']; + if (fileUris) { + for (let f of fileUris) { + const fileUri = this.argToUri(f); + if (fileUri) { + const path = this.parseUri(hasWorkspaceFileExtension(f) ? { workspaceUri: fileUri } : { fileUri }, parseOptions); + if (path) { + pathsToOpen.push(path); + } } } } // folder or file paths - const cliArgs = asArray(cli._); + const cliArgs = cli._; for (let cliArg of cliArgs) { const path = this.parsePath(cliArg, parseOptions); if (path) { @@ -1166,7 +1171,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { return { openFolderInNewWindow: !!openFolderInNewWindow, openFilesInNewWindow }; } - openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string | string[], openConfig: IOpenConfiguration): void { + openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): void { // Reload an existing extension development host window on the same path // We currently do not allow more than one extension development window @@ -1178,8 +1183,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService { return; } - let folderUris = asArray(openConfig.cli['folder-uri']); - let fileUris = asArray(openConfig.cli['file-uri']); + let folderUris = openConfig.cli['folder-uri'] || []; + let fileUris = openConfig.cli['file-uri'] || []; let cliArgs = openConfig.cli._; // Fill in previously opened workspace unless an explicit path is provided and we are not unit testing @@ -1203,10 +1208,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } } - if (!Array.isArray(extensionDevelopmentPath)) { - extensionDevelopmentPath = [extensionDevelopmentPath]; - } - let authority = ''; for (let p of extensionDevelopmentPath) { if (p.match(/^[a-zA-Z][a-zA-Z0-9\+\-\.]+:/)) { @@ -1599,7 +1600,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } getLastActiveWindowForAuthority(remoteAuthority: string | undefined): ICodeWindow | undefined { - return getLastActiveWindow(WindowsManager.WINDOWS.filter(w => w.remoteAuthority === remoteAuthority)); + return getLastActiveWindow(WindowsManager.WINDOWS.filter(window => window.remoteAuthority === remoteAuthority)); } openNewWindow(context: OpenContext, options?: INewWindowOptions): ICodeWindow[] { @@ -1642,13 +1643,13 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } sendToAll(channel: string, payload?: any, windowIdsToIgnore?: number[]): void { - WindowsManager.WINDOWS.forEach(w => { - if (windowIdsToIgnore && windowIdsToIgnore.indexOf(w.id) >= 0) { - return; // do not send if we are instructed to ignore it + for (const window of WindowsManager.WINDOWS) { + if (windowIdsToIgnore && windowIdsToIgnore.indexOf(window.id) >= 0) { + continue; // do not send if we are instructed to ignore it } - w.sendWhenReady(channel, payload); - }); + window.sendWhenReady(channel, payload); + } } getFocusedWindow(): ICodeWindow | undefined { @@ -1661,7 +1662,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } getWindowById(windowId: number): ICodeWindow | undefined { - const res = WindowsManager.WINDOWS.filter(w => w.id === windowId); + const res = WindowsManager.WINDOWS.filter(window => window.id === windowId); if (res && res.length === 1) { return res[0]; } diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index d5cfa715e8..20a1ad5063 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -4,8 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { spawn, ChildProcess, SpawnOptions } from 'child_process'; -import { assign } from 'vs/base/common/objects'; -import { buildHelpMessage, buildVersionMessage, addArg, createWaitMarkerFile } from 'vs/platform/environment/node/argv'; +import { buildHelpMessage, buildVersionMessage, addArg, createWaitMarkerFile, OPTIONS } from 'vs/platform/environment/node/argv'; import { parseCLIProcessArgv } from 'vs/platform/environment/node/argvHelper'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; import product from 'vs/platform/product/node/product'; @@ -47,7 +46,7 @@ export async function main(argv: string[]): Promise { // Help if (args.help) { const executable = `${product.applicationName}${os.platform() === 'win32' ? '.exe' : ''}`; - console.log(buildHelpMessage(product.nameLong, executable, pkg.version)); + console.log(buildHelpMessage(product.nameLong, executable, pkg.version, OPTIONS)); } // Version Info @@ -118,10 +117,15 @@ export async function main(argv: string[]): Promise { // Just Code else { - const env = assign({}, process.env, { + const env: NodeJS.ProcessEnv = { + ...process.env, 'VSCODE_CLI': '1', // this will signal Code that it was spawned from this module 'ELECTRON_NO_ATTACH_CONSOLE': '1' - }); + }; + + if (args['force-user-env']) { + env['VSCODE_FORCE_USER_ENV'] = '1'; + } delete env['ELECTRON_RUN_AS_NODE']; diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 17a4b1a2e9..43ecdb988f 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -83,23 +83,14 @@ export class Main { async run(argv: ParsedArgs): Promise { if (argv['install-source']) { await this.setInstallSource(argv['install-source']); - } else if (argv['list-extensions']) { await this.listExtensions(!!argv['show-versions'], argv['category']); - } else if (argv['install-extension']) { - const arg = argv['install-extension']; - const args: string[] = typeof arg === 'string' ? [arg] : arg; - await this.installExtensions(args, !!argv['force']); - + await this.installExtensions(argv['install-extension'], !!argv['force']); } else if (argv['uninstall-extension']) { - const arg = argv['uninstall-extension']; - const ids: string[] = typeof arg === 'string' ? [arg] : arg; - await this.uninstallExtension(ids); + await this.uninstallExtension(argv['uninstall-extension']); } else if (argv['locate-extension']) { - const arg = argv['locate-extension']; - const ids: string[] = typeof arg === 'string' ? [arg] : arg; - await this.locateExtension(ids); + await this.locateExtension(argv['locate-extension']); } else if (argv['telemetry']) { console.log(buildTelemetryMessage(this.environmentService.appRoot, this.environmentService.extensionsPath ? this.environmentService.extensionsPath : undefined)); } @@ -359,7 +350,7 @@ export async function main(argv: ParsedArgs): Promise { const config: ITelemetryServiceConfig = { appender: combinedAppender(...appenders), - commonProperties: resolveCommonProperties(product.commit, pkg.version, stateService.getItem('telemetry.machineId'), installSourcePath), + commonProperties: resolveCommonProperties(product.commit, pkg.version, stateService.getItem('telemetry.machineId'), product.msftInternalDomains, installSourcePath), piiPaths: extensionsPath ? [appRoot, extensionsPath] : [appRoot] }; diff --git a/src/vs/code/node/shellEnv.ts b/src/vs/code/node/shellEnv.ts index 856fd9f96e..1ca11320f3 100644 --- a/src/vs/code/node/shellEnv.ts +++ b/src/vs/code/node/shellEnv.ts @@ -98,7 +98,7 @@ export function getShellEnvironment(logService: ILogService, environmentService: } else if (isWindows) { logService.trace('getShellEnvironment: running on Windows, skipping'); _shellEnv = Promise.resolve({}); - } else if (process.env['VSCODE_CLI'] === '1') { + } else if (process.env['VSCODE_CLI'] === '1' && process.env['VSCODE_FORCE_USER_ENV'] !== '1') { logService.trace('getShellEnvironment: running on CLI, skipping'); _shellEnv = Promise.resolve({}); } else { diff --git a/src/vs/code/node/windowsFinder.ts b/src/vs/code/node/windowsFinder.ts index a17433b363..754dd46d1d 100644 --- a/src/vs/code/node/windowsFinder.ts +++ b/src/vs/code/node/windowsFinder.ts @@ -14,7 +14,7 @@ export interface ISimpleWindow { openedWorkspace?: IWorkspaceIdentifier; openedFolderUri?: URI; - extensionDevelopmentPath?: string | string[]; + extensionDevelopmentPath?: string[]; lastFocusTime: number; } @@ -95,30 +95,17 @@ export function findWindowOnWorkspace(windows: W[], wor return null; } -export function findWindowOnExtensionDevelopmentPath(windows: W[], extensionDevelopmentPath: string | string[]): W | null { +export function findWindowOnExtensionDevelopmentPath(windows: W[], extensionDevelopmentPaths: string[]): W | null { const matches = (uriString: string): boolean => { - if (Array.isArray(extensionDevelopmentPath)) { - return extensionDevelopmentPath.some(p => extpath.isEqual(p, uriString, !platform.isLinux /* ignorecase */)); - } else if (extensionDevelopmentPath) { - return extpath.isEqual(extensionDevelopmentPath, uriString, !platform.isLinux /* ignorecase */); - } - return false; + return extensionDevelopmentPaths.some(p => extpath.isEqual(p, uriString, !platform.isLinux /* ignorecase */)); }; for (const window of windows) { // match on extension development path. The path can be one or more paths or uri strings, using paths.isEqual is not 100% correct but good enough - - if (window.extensionDevelopmentPath) { - if (Array.isArray(window.extensionDevelopmentPath)) { - if (window.extensionDevelopmentPath.some(p => matches(p))) { - return window; - } - } else if (window.extensionDevelopmentPath) { - if (matches(window.extensionDevelopmentPath)) { - return window; - } - } + const currPaths = window.extensionDevelopmentPath; + if (currPaths && currPaths.some(p => matches(p))) { + return window; } } diff --git a/src/vs/code/test/node/argv.test.ts b/src/vs/code/test/node/argv.test.ts index 31aac0ee98..0dee81f772 100644 --- a/src/vs/code/test/node/argv.test.ts +++ b/src/vs/code/test/node/argv.test.ts @@ -4,29 +4,28 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { formatOptions, Option, addArg } from 'vs/platform/environment/node/argv'; -import { ParsedArgs } from 'vs/platform/environment/common/environment'; suite('formatOptions', () => { - function o(id: keyof ParsedArgs, description: string): Option { + function o(description: string): Option { return { - id, description, type: 'string' + description, type: 'string' }; } test('Text should display small columns correctly', () => { assert.deepEqual( - formatOptions([ - o('add', 'bar') - ], 80), + formatOptions({ + 'add': o('bar') + }, 80), [' --add bar'] ); assert.deepEqual( - formatOptions([ - o('add', 'bar'), - o('wait', 'ba'), - o('trace', 'b') - ], 80), + formatOptions({ + 'add': o('bar'), + 'wait': o('ba'), + 'trace': o('b') + }, 80), [ ' --add bar', ' --wait ba', @@ -36,9 +35,9 @@ suite('formatOptions', () => { test('Text should wrap', () => { assert.deepEqual( - formatOptions([ - o('add', ('bar ').repeat(9)) - ], 40), + formatOptions({ + 'add': o(('bar ').repeat(9)) + }, 40), [ ' --add bar bar bar bar bar bar bar bar', ' bar' @@ -47,9 +46,9 @@ suite('formatOptions', () => { test('Text should revert to the condensed view when the terminal is too narrow', () => { assert.deepEqual( - formatOptions([ - o('add', ('bar ').repeat(9)) - ], 30), + formatOptions({ + 'add': o(('bar ').repeat(9)) + }, 30), [ ' --add', ' bar bar bar bar bar bar bar bar bar ' diff --git a/src/vs/editor/browser/config/charWidthReader.ts b/src/vs/editor/browser/config/charWidthReader.ts index af8d09db9d..5e66e7c887 100644 --- a/src/vs/editor/browser/config/charWidthReader.ts +++ b/src/vs/editor/browser/config/charWidthReader.ts @@ -93,8 +93,7 @@ class DomCharWidthReader { container.appendChild(italicDomNode); const testElements: HTMLSpanElement[] = []; - for (let i = 0, len = this._requests.length; i < len; i++) { - const request = this._requests[i]; + for (const request of this._requests) { let parent: HTMLElement; if (request.type === CharWidthRequestType.Regular) { @@ -113,7 +112,7 @@ class DomCharWidthReader { DomCharWidthReader._render(testElement, request); parent!.appendChild(testElement); - testElements[i] = testElement; + testElements.push(testElement); } this._container = container; diff --git a/src/vs/editor/browser/config/configuration.ts b/src/vs/editor/browser/config/configuration.ts index e3f2b36904..a2b2b5d83b 100644 --- a/src/vs/editor/browser/config/configuration.ts +++ b/src/vs/editor/browser/config/configuration.ts @@ -11,7 +11,7 @@ import * as platform from 'vs/base/common/platform'; import { CharWidthRequest, CharWidthRequestType, readCharWidths } from 'vs/editor/browser/config/charWidthReader'; import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver'; import { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig'; -import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo'; import { IDimension } from 'vs/editor/common/editorCommon'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; @@ -320,7 +320,7 @@ export class Configuration extends CommonEditorConfiguration { this._register(CSSBasedConfiguration.INSTANCE.onDidChange(() => this._onCSSBasedConfigurationChanged())); - if (this._validatedOptions.automaticLayout) { + if (this._validatedOptions.get(EditorOption.automaticLayout)) { this._elementSizeObserver.startObserving(); } diff --git a/src/vs/editor/browser/controller/coreCommands.ts b/src/vs/editor/browser/controller/coreCommands.ts index 415b4574a4..f9779cc326 100644 --- a/src/vs/editor/browser/controller/coreCommands.ts +++ b/src/vs/editor/browser/controller/coreCommands.ts @@ -294,7 +294,7 @@ export namespace CoreNavigationCommands { CursorMoveCommands.moveTo(cursors.context, cursors.getPrimaryCursor(), this._inSelectionMode, args.position, args.viewPosition) ] ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } } @@ -322,7 +322,7 @@ export namespace CoreNavigationCommands { toViewLineNumber: result.toLineNumber, toViewVisualColumn: result.toVisualColumn }); - cursors.reveal(true, (result.reversed ? RevealTarget.TopMost : RevealTarget.BottomMost), ScrollType.Smooth); + cursors.reveal(args.source, true, (result.reversed ? RevealTarget.TopMost : RevealTarget.BottomMost), ScrollType.Smooth); } protected abstract _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult; @@ -343,12 +343,8 @@ export namespace CoreNavigationCommands { const validatedPosition = context.model.validatePosition(args.position); const validatedViewPosition = context.validateViewPosition(new Position(args.viewPosition.lineNumber, args.viewPosition.column), validatedPosition); - let fromViewLineNumber = prevColumnSelectData.fromViewLineNumber; - let fromViewVisualColumn = prevColumnSelectData.fromViewVisualColumn; - if (!prevColumnSelectData.isReal && args.setAnchorIfNotSet) { - fromViewLineNumber = validatedViewPosition.lineNumber; - fromViewVisualColumn = args.mouseColumn - 1; - } + let fromViewLineNumber = args.doColumnSelect ? prevColumnSelectData.fromViewLineNumber : validatedViewPosition.lineNumber; + let fromViewVisualColumn = args.doColumnSelect ? prevColumnSelectData.fromViewVisualColumn : args.mouseColumn - 1; return ColumnSelection.columnSelect(context.config, context.viewModel, fromViewLineNumber, fromViewVisualColumn, validatedViewPosition.lineNumber, args.mouseColumn - 1); } }); @@ -492,7 +488,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, CursorMoveCommands.move(cursors.context, cursors.getAll(), args) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(source, true, RevealTarget.Primary, ScrollType.Smooth); } } @@ -831,7 +827,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, CursorMoveCommands.moveToBeginningOfLine(cursors.context, cursors.getAll(), this._inSelectionMode) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } } @@ -880,7 +876,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, this._exec(cursors.context, cursors.getAll()) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } private _exec(context: CursorContext, cursors: CursorState[]): PartialCursorState[] { @@ -910,7 +906,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, CursorMoveCommands.moveToEndOfLine(cursors.context, cursors.getAll(), this._inSelectionMode) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } } @@ -959,7 +955,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, this._exec(cursors.context, cursors.getAll()) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } private _exec(context: CursorContext, cursors: CursorState[]): PartialCursorState[] { @@ -990,7 +986,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, CursorMoveCommands.moveToBeginningOfBuffer(cursors.context, cursors.getAll(), this._inSelectionMode) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } } @@ -1034,7 +1030,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, CursorMoveCommands.moveToEndOfBuffer(cursors.context, cursors.getAll(), this._inSelectionMode) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } } @@ -1253,7 +1249,7 @@ export namespace CoreNavigationCommands { CursorMoveCommands.word(cursors.context, cursors.getPrimaryCursor(), this._inSelectionMode, args.position) ] ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } } @@ -1313,7 +1309,7 @@ export namespace CoreNavigationCommands { CursorMoveCommands.line(cursors.context, cursors.getPrimaryCursor(), this._inSelectionMode, args.position, args.viewPosition) ] ); - cursors.reveal(false, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, false, RevealTarget.Primary, ScrollType.Smooth); } } @@ -1385,7 +1381,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, CursorMoveCommands.expandLineSelection(cursors.context, cursors.getAll()) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } }); @@ -1413,7 +1409,7 @@ export namespace CoreNavigationCommands { CursorMoveCommands.cancelSelection(cursors.context, cursors.getPrimaryCursor()) ] ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } }); @@ -1440,7 +1436,7 @@ export namespace CoreNavigationCommands { cursors.getPrimaryCursor() ] ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } }); @@ -1488,7 +1484,7 @@ export namespace CoreNavigationCommands { const viewRange = cursors.context.convertModelRangeToViewRange(range); - cursors.revealRange(false, viewRange, revealAt, ScrollType.Smooth); + cursors.revealRange(args.source, false, viewRange, revealAt, ScrollType.Smooth); } }); diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index e9696bbe29..26741a1955 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -21,6 +21,8 @@ import { HorizontalRange } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + /** * Merges mouse events when mouse move events are throttled @@ -111,7 +113,7 @@ export class MouseHandler extends ViewEventHandler { const onMouseWheel = (browserEvent: IMouseWheelEvent) => { this.viewController.emitMouseWheel(browserEvent); - if (!this._context.configuration.editor.viewInfo.mouseWheelZoom) { + if (!this._context.configuration.options.get(EditorOption.mouseWheelZoom)) { return; } const e = new StandardWheelEvent(browserEvent); @@ -216,7 +218,7 @@ export class MouseHandler extends ViewEventHandler { const targetIsContent = (t.type === editorBrowser.MouseTargetType.CONTENT_TEXT || t.type === editorBrowser.MouseTargetType.CONTENT_EMPTY); const targetIsGutter = (t.type === editorBrowser.MouseTargetType.GUTTER_GLYPH_MARGIN || t.type === editorBrowser.MouseTargetType.GUTTER_LINE_NUMBERS || t.type === editorBrowser.MouseTargetType.GUTTER_LINE_DECORATIONS); const targetIsLineNumbers = (t.type === editorBrowser.MouseTargetType.GUTTER_LINE_NUMBERS); - const selectOnLineNumbers = this._context.configuration.editor.viewInfo.selectOnLineNumbers; + const selectOnLineNumbers = this._context.configuration.options.get(EditorOption.selectOnLineNumbers); const targetIsViewZone = (t.type === editorBrowser.MouseTargetType.CONTENT_VIEW_ZONE || t.type === editorBrowser.MouseTargetType.GUTTER_VIEW_ZONE); const targetIsWidget = (t.type === editorBrowser.MouseTargetType.CONTENT_WIDGET); @@ -351,8 +353,10 @@ class MouseDownOperation extends Disposable { // Overwrite the detail of the MouseEvent, as it will be sent out in an event and contributions might rely on it. e.detail = this._mouseState.count; - if (!this._context.configuration.editor.readOnly - && this._context.configuration.editor.dragAndDrop + const options = this._context.configuration.options; + + if (!options.get(EditorOption.readOnly) + && options.get(EditorOption.dragAndDrop) && !this._mouseState.altKey // we don't support multiple mouse && e.detail < 2 // only single click on a selection can work && !this._isActive // the mouse is not down yet diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index c681bf6732..a096fd6065 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -10,7 +10,7 @@ import { ClientCoordinates, EditorMouseEvent, EditorPagePosition, PageCoordinate import { PartFingerprint, PartFingerprints } from 'vs/editor/browser/view/viewPart'; import { ViewLine } from 'vs/editor/browser/viewParts/lines/viewLine'; import { IViewCursorRenderData } from 'vs/editor/browser/viewParts/viewCursors/viewCursor'; -import { EditorLayoutInfo } from 'vs/editor/common/config/editorOptions'; +import { EditorLayoutInfo, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range as EditorRange } from 'vs/editor/common/core/range'; import { HorizontalRange } from 'vs/editor/common/view/renderingContext'; @@ -239,10 +239,11 @@ export class HitTestContext { constructor(context: ViewContext, viewHelper: IPointerHandlerHelper, lastViewCursorsRenderData: IViewCursorRenderData[]) { this.model = context.model; - this.layoutInfo = context.configuration.editor.layoutInfo; + const options = context.configuration.options; + this.layoutInfo = options.get(EditorOption.layoutInfo); this.viewDomNode = viewHelper.viewDomNode; - this.lineHeight = context.configuration.editor.lineHeight; - this.typicalHalfwidthCharacterWidth = context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; + this.lineHeight = options.get(EditorOption.lineHeight); + this.typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; this.lastViewCursorsRenderData = lastViewCursorsRenderData; this._context = context; this._viewHelper = viewHelper; @@ -713,9 +714,10 @@ export class MouseTargetFactory { } public getMouseColumn(editorPos: EditorPagePosition, pos: PageCoordinates): number { - const layoutInfo = this._context.configuration.editor.layoutInfo; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); const mouseContentHorizontalOffset = this._context.viewLayout.getCurrentScrollLeft() + pos.x - editorPos.x - layoutInfo.contentLeft; - return MouseTargetFactory._getMouseColumn(mouseContentHorizontalOffset, this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth); + return MouseTargetFactory._getMouseColumn(mouseContentHorizontalOffset, options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth); } public static _getMouseColumn(mouseContentHorizontalOffset: number, typicalHalfwidthCharacterWidth: number): number { diff --git a/src/vs/editor/browser/controller/textAreaHandler.ts b/src/vs/editor/browser/controller/textAreaHandler.ts index 80aab9c08f..49bf05b4f9 100644 --- a/src/vs/editor/browser/controller/textAreaHandler.ts +++ b/src/vs/editor/browser/controller/textAreaHandler.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./textAreaHandler'; +import * as nls from 'vs/nls'; import * as browser from 'vs/base/browser/browser'; import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -16,7 +17,7 @@ import { ViewController } from 'vs/editor/browser/view/viewController'; import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart'; import { LineNumbersOverlay } from 'vs/editor/browser/viewParts/lineNumbers/lineNumbers'; import { Margin } from 'vs/editor/browser/viewParts/margin/margin'; -import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions'; +import { RenderLineNumbersType, EditorOption, IComputedEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { WordCharacterClass, getMapForWordSeparators } from 'vs/editor/common/controller/wordCharacterClassifier'; import { Position } from 'vs/editor/common/core/position'; @@ -91,12 +92,13 @@ export class TextAreaHandler extends ViewPart { private readonly _viewController: ViewController; private readonly _viewHelper: ITextAreaHandlerHelper; + private _scrollLeft: number; + private _scrollTop: number; + private _accessibilitySupport: AccessibilitySupport; private _contentLeft: number; private _contentWidth: number; private _contentHeight: number; - private _scrollLeft: number; - private _scrollTop: number; private _fontInfo: BareFontInfo; private _lineHeight: number; private _emptySelectionClipboard: boolean; @@ -117,19 +119,20 @@ export class TextAreaHandler extends ViewPart { this._viewController = viewController; this._viewHelper = viewHelper; - - const conf = this._context.configuration.editor; - - this._accessibilitySupport = conf.accessibilitySupport; - this._contentLeft = conf.layoutInfo.contentLeft; - this._contentWidth = conf.layoutInfo.contentWidth; - this._contentHeight = conf.layoutInfo.contentHeight; this._scrollLeft = 0; this._scrollTop = 0; - this._fontInfo = conf.fontInfo; - this._lineHeight = conf.lineHeight; - this._emptySelectionClipboard = conf.emptySelectionClipboard; - this._copyWithSyntaxHighlighting = conf.copyWithSyntaxHighlighting; + + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._accessibilitySupport = options.get(EditorOption.accessibilitySupport); + this._contentLeft = layoutInfo.contentLeft; + this._contentWidth = layoutInfo.contentWidth; + this._contentHeight = layoutInfo.contentHeight; + this._fontInfo = options.get(EditorOption.fontInfo); + this._lineHeight = options.get(EditorOption.lineHeight); + this._emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard); + this._copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting); this._visibleTextArea = null; this._selections = [new Selection(1, 1, 1, 1)]; @@ -143,7 +146,7 @@ export class TextAreaHandler extends ViewPart { this.textArea.setAttribute('autocapitalize', 'off'); this.textArea.setAttribute('autocomplete', 'off'); this.textArea.setAttribute('spellcheck', 'false'); - this.textArea.setAttribute('aria-label', conf.viewInfo.ariaLabel); + this.textArea.setAttribute('aria-label', this._getAriaLabel(options)); this.textArea.setAttribute('role', 'textbox'); this.textArea.setAttribute('aria-multiline', 'true'); this.textArea.setAttribute('aria-haspopup', 'false'); @@ -280,6 +283,7 @@ export class TextAreaHandler extends ViewPart { const column = this._selections[0].startColumn; this._context.privateViewEventBus.emit(new viewEvents.ViewRevealRangeRequestEvent( + 'keyboard', new Range(lineNumber, column, lineNumber, column), viewEvents.VerticalRevealType.Simple, true, @@ -340,7 +344,7 @@ export class TextAreaHandler extends ViewPart { private _getWordBeforePosition(position: Position): string { const lineContent = this._context.model.getLineContent(position.lineNumber); - const wordSeparators = getMapForWordSeparators(this._context.configuration.editor.wordSeparators); + const wordSeparators = getMapForWordSeparators(this._context.configuration.options.get(EditorOption.wordSeparators)); let column = position.column; let distance = 0; @@ -367,35 +371,33 @@ export class TextAreaHandler extends ViewPart { return ''; } + private _getAriaLabel(options: IComputedEditorOptions): string { + const accessibilitySupport = options.get(EditorOption.accessibilitySupport); + if (accessibilitySupport === AccessibilitySupport.Disabled) { + return nls.localize('accessibilityOffAriaLabel', "The editor is not accessible at this time. Press Alt+F1 for options."); + } + return options.get(EditorOption.ariaLabel); + } + // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - const conf = this._context.configuration.editor; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); - if (e.fontInfo) { - this._fontInfo = conf.fontInfo; - } - if (e.viewInfo) { - this.textArea.setAttribute('aria-label', conf.viewInfo.ariaLabel); - } - if (e.layoutInfo) { - this._contentLeft = conf.layoutInfo.contentLeft; - this._contentWidth = conf.layoutInfo.contentWidth; - this._contentHeight = conf.layoutInfo.contentHeight; - } - if (e.lineHeight) { - this._lineHeight = conf.lineHeight; - } - if (e.accessibilitySupport) { - this._accessibilitySupport = conf.accessibilitySupport; + this._accessibilitySupport = options.get(EditorOption.accessibilitySupport); + this._contentLeft = layoutInfo.contentLeft; + this._contentWidth = layoutInfo.contentWidth; + this._contentHeight = layoutInfo.contentHeight; + this._fontInfo = options.get(EditorOption.fontInfo); + this._lineHeight = options.get(EditorOption.lineHeight); + this._emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard); + this._copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting); + this.textArea.setAttribute('aria-label', this._getAriaLabel(options)); + + if (e.hasChanged(EditorOption.accessibilitySupport)) { this._textAreaInput.writeScreenReaderContent('strategy changed'); } - if (e.emptySelectionClipboard) { - this._emptySelectionClipboard = conf.emptySelectionClipboard; - } - if (e.copyWithSyntaxHighlighting) { - this._copyWithSyntaxHighlighting = conf.copyWithSyntaxHighlighting; - } return true; } @@ -544,10 +546,12 @@ export class TextAreaHandler extends ViewPart { tac.setWidth(1); tac.setHeight(1); - if (this._context.configuration.editor.viewInfo.glyphMargin) { + const options = this._context.configuration.options; + + if (options.get(EditorOption.glyphMargin)) { tac.setClassName('monaco-editor-background textAreaCover ' + Margin.OUTER_CLASS_NAME); } else { - if (this._context.configuration.editor.viewInfo.renderLineNumbers !== RenderLineNumbersType.Off) { + if (options.get(EditorOption.lineNumbers).renderType !== RenderLineNumbersType.Off) { tac.setClassName('monaco-editor-background textAreaCover ' + LineNumbersOverlay.CLASS_NAME); } else { tac.setClassName('monaco-editor-background textAreaCover'); diff --git a/src/vs/editor/browser/controller/textAreaInput.ts b/src/vs/editor/browser/controller/textAreaInput.ts index 56b631a78c..5ae7510e36 100644 --- a/src/vs/editor/browser/controller/textAreaInput.ts +++ b/src/vs/editor/browser/controller/textAreaInput.ts @@ -54,6 +54,11 @@ const enum TextAreaInputEventType { blur } +interface CompositionEvent extends UIEvent { + readonly data: string; + readonly locale: string; +} + /** * Writes screen reader content to the textarea and is able to analyze its input events to generate: * - onCut diff --git a/src/vs/editor/browser/core/keybindingCancellation.ts b/src/vs/editor/browser/core/keybindingCancellation.ts index b79fc92418..a3123fd563 100644 --- a/src/vs/editor/browser/core/keybindingCancellation.ts +++ b/src/vs/editor/browser/core/keybindingCancellation.ts @@ -17,7 +17,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; const IEditorCancellationTokens = createDecorator('IEditorCancelService'); interface IEditorCancellationTokens { - _serviceBrand: any; + _serviceBrand: undefined; add(editor: ICodeEditor, cts: CancellationTokenSource): () => void; cancel(editor: ICodeEditor): void; } @@ -26,7 +26,7 @@ const ctxCancellableOperation = new RawContextKey('cancellableOperation', false) registerSingleton(IEditorCancellationTokens, class implements IEditorCancellationTokens { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _tokens = new WeakMap, tokens: LinkedList }>(); diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index c099b8be2f..ebbb8dc5f2 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -6,7 +6,7 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { IMouseEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; import { IDisposable } from 'vs/base/common/lifecycle'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { OverviewRulerPosition, ConfigurationChangedEvent, EditorLayoutInfo, IComputedEditorOptions, EditorOption, FindComputedEditorOptionValueById, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { ICursors } from 'vs/editor/common/controller/cursorCommon'; import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { IPosition, Position } from 'vs/editor/common/core/position'; @@ -315,7 +315,7 @@ export interface IOverviewRuler { getDomNode(): HTMLElement; dispose(): void; setZones(zones: OverviewRulerZone[]): void; - setLayout(position: editorOptions.OverviewRulerPosition): void; + setLayout(position: OverviewRulerPosition): void; } /** @@ -351,7 +351,7 @@ export interface ICodeEditor extends editorCommon.IEditor { * An event emitted when the configuration of the editor has changed. (e.g. `editor.updateOptions()`) * @event */ - onDidChangeConfiguration(listener: (e: editorOptions.IConfigurationChangedEvent) => void): IDisposable; + onDidChangeConfiguration(listener: (e: ConfigurationChangedEvent) => void): IDisposable; /** * An event emitted when the cursor position has changed. * @event @@ -481,7 +481,7 @@ export interface ICodeEditor extends editorCommon.IEditor { * An event emitted when the layout of the editor has changed. * @event */ - onDidLayoutChange(listener: (e: editorOptions.EditorLayoutInfo) => void): IDisposable; + onDidLayoutChange(listener: (e: EditorLayoutInfo) => void): IDisposable; /** * An event emitted when the scroll in the editor has changed. * @event @@ -532,15 +532,19 @@ export interface ICodeEditor extends editorCommon.IEditor { setModel(model: ITextModel | null): void; /** - * Returns the current editor's configuration - */ - getConfiguration(): editorOptions.InternalEditorOptions; - - /** - * Returns the 'raw' editor's configuration (without any validation or defaults). * @internal */ - getRawConfiguration(): editorOptions.IEditorOptions; + getOptions(): IComputedEditorOptions; + + /** + * @internal + */ + getOption(id: T): FindComputedEditorOptionValueById; + + /** + * Returns the editor's configuration (without any validation or defaults). + */ + getRawOptions(): IEditorOptions; /** * Get value of the current model attached to this editor. @@ -655,7 +659,7 @@ export interface ICodeEditor extends editorCommon.IEditor { /** * Get the layout info for the editor. */ - getLayoutInfo(): editorOptions.EditorLayoutInfo; + getLayoutInfo(): EditorLayoutInfo; /** * Returns the ranges that are currently visible. diff --git a/src/vs/editor/browser/services/abstractCodeEditorService.ts b/src/vs/editor/browser/services/abstractCodeEditorService.ts index fab31e80c7..945cd8b2d7 100644 --- a/src/vs/editor/browser/services/abstractCodeEditorService.ts +++ b/src/vs/editor/browser/services/abstractCodeEditorService.ts @@ -13,7 +13,7 @@ import { IResourceInput } from 'vs/platform/editor/common/editor'; export abstract class AbstractCodeEditorService extends Disposable implements ICodeEditorService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _onCodeEditorAdd: Emitter = this._register(new Emitter()); public readonly onCodeEditorAdd: Event = this._onCodeEditorAdd.event; diff --git a/src/vs/editor/browser/services/bulkEditService.ts b/src/vs/editor/browser/services/bulkEditService.ts index 00c9b07738..246270a0c3 100644 --- a/src/vs/editor/browser/services/bulkEditService.ts +++ b/src/vs/editor/browser/services/bulkEditService.ts @@ -21,7 +21,7 @@ export interface IBulkEditResult { } export interface IBulkEditService { - _serviceBrand: any; + _serviceBrand: undefined; apply(edit: WorkspaceEdit, options?: IBulkEditOptions): Promise; } diff --git a/src/vs/editor/browser/services/codeEditorService.ts b/src/vs/editor/browser/services/codeEditorService.ts index 5f019fd359..c8f84e3119 100644 --- a/src/vs/editor/browser/services/codeEditorService.ts +++ b/src/vs/editor/browser/services/codeEditorService.ts @@ -13,7 +13,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export const ICodeEditorService = createDecorator('codeEditorService'); export interface ICodeEditorService { - _serviceBrand: any; + _serviceBrand: undefined; readonly onCodeEditorAdd: Event; readonly onCodeEditorRemove: Event; diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index 51d883f386..df7b412c69 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -13,12 +13,11 @@ import { equalsIgnoreCase } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IOpener, IOpenerService, IValidator } from 'vs/platform/opener/common/opener'; export class OpenerService extends Disposable implements IOpenerService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private readonly _openers = new LinkedList(); private readonly _validators = new LinkedList(); diff --git a/src/vs/editor/browser/view/viewController.ts b/src/vs/editor/browser/view/viewController.ts index e6847ff319..12a1849932 100644 --- a/src/vs/editor/browser/view/viewController.ts +++ b/src/vs/editor/browser/view/viewController.ts @@ -12,6 +12,7 @@ import { Selection } from 'vs/editor/common/core/selection'; import { IConfiguration } from 'vs/editor/common/editorCommon'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface IMouseDispatchData { position: Position; @@ -107,7 +108,7 @@ export class ViewController { } private _hasMulticursorModifier(data: IMouseDispatchData): boolean { - switch (this.configuration.editor.multiCursorModifier) { + switch (this.configuration.options.get(EditorOption.multiCursorModifier)) { case 'altKey': return data.altKey; case 'ctrlKey': @@ -119,7 +120,7 @@ export class ViewController { } private _hasNonMulticursorModifier(data: IMouseDispatchData): boolean { - switch (this.configuration.editor.multiCursorModifier) { + switch (this.configuration.options.get(EditorOption.multiCursorModifier)) { case 'altKey': return data.ctrlKey || data.metaKey; case 'ctrlKey': @@ -132,11 +133,7 @@ export class ViewController { public dispatchMouse(data: IMouseDispatchData): void { if (data.middleButton) { - if (data.inSelectionMode) { - this._columnSelect(data.position, data.mouseColumn, true); - } else { - this.moveTo(data.position); - } + this._columnSelect(data.position, data.mouseColumn, data.inSelectionMode); } else if (data.startedOnLineNumbers) { // If the dragging started on the gutter, then have operations work on the entire line if (this._hasMulticursorModifier(data)) { @@ -182,7 +179,7 @@ export class ViewController { if (this._hasMulticursorModifier(data)) { if (!this._hasNonMulticursorModifier(data)) { if (data.shiftKey) { - this._columnSelect(data.position, data.mouseColumn, false); + this._columnSelect(data.position, data.mouseColumn, true); } else { // Do multi-cursor operations only when purely alt is pressed if (data.inSelectionMode) { @@ -222,13 +219,13 @@ export class ViewController { this._execMouseCommand(CoreNavigationCommands.MoveToSelect, this._usualArgs(viewPosition)); } - private _columnSelect(viewPosition: Position, mouseColumn: number, setAnchorIfNotSet: boolean): void { + private _columnSelect(viewPosition: Position, mouseColumn: number, doColumnSelect: boolean): void { viewPosition = this._validateViewColumn(viewPosition); this._execMouseCommand(CoreNavigationCommands.ColumnSelect, { position: this._convertViewToModelPosition(viewPosition), viewPosition: viewPosition, mouseColumn: mouseColumn, - setAnchorIfNotSet: setAnchorIfNotSet + doColumnSelect: doColumnSelect }); } diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index 2837bfe182..ae67d9315f 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -48,6 +48,8 @@ import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData' import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; import { IThemeService, getThemeTypeSelector } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export interface IContentWidgetData { widget: editorBrowser.IContentWidget; @@ -218,7 +220,7 @@ export class View extends ViewEventHandler { this.domNode.appendChild(this.overflowGuardContainer); this.domNode.appendChild(this.contentWidgets.overflowingContentWidgetsDomNode); - this._setLayout(); + this._applyLayout(); // Pointer handler this.pointerHandler = this._register(new PointerHandler(this._context, viewController, this.createPointerHandlerHelper())); @@ -280,8 +282,10 @@ export class View extends ViewEventHandler { }; } - private _setLayout(): void { - const layoutInfo = this._context.configuration.editor.layoutInfo; + private _applyLayout(): void { + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + this.domNode.setWidth(layoutInfo.width); this.domNode.setHeight(layoutInfo.height); @@ -290,23 +294,18 @@ export class View extends ViewEventHandler { this.linesContent.setWidth(1000000); this.linesContent.setHeight(1000000); - } private getEditorClassName() { const focused = this._textAreaHandler.isFocused() ? ' focused' : ''; - return this._context.configuration.editor.editorClassName + ' ' + getThemeTypeSelector(this._context.theme.type) + focused; + return this._context.configuration.options.get(EditorOption.editorClassName) + ' ' + getThemeTypeSelector(this._context.theme.type) + focused; } // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.editorClassName) { - this.domNode.setClassName(this.getEditorClassName()); - } - if (e.layoutInfo) { - this._setLayout(); - } + this.domNode.setClassName(this.getEditorClassName()); + this._applyLayout(); return false; } public onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean { diff --git a/src/vs/editor/browser/view/viewLayer.ts b/src/vs/editor/browser/view/viewLayer.ts index 9eaf36289d..d2252ddc62 100644 --- a/src/vs/editor/browser/view/viewLayer.ts +++ b/src/vs/editor/browser/view/viewLayer.ts @@ -7,6 +7,7 @@ import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { IStringBuilder, createStringBuilder } from 'vs/editor/common/core/stringBuilder'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; /** * Represents a visible line @@ -269,7 +270,10 @@ export class VisibleLinesCollection { // ---- begin view event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - return e.layoutInfo; + if (e.hasChanged(EditorOption.layoutInfo)) { + return true; + } + return false; } public onFlushed(e: viewEvents.ViewFlushedEvent): boolean { diff --git a/src/vs/editor/browser/view/viewOverlays.ts b/src/vs/editor/browser/view/viewOverlays.ts index 3c4e457ae5..4977ec308c 100644 --- a/src/vs/editor/browser/view/viewOverlays.ts +++ b/src/vs/editor/browser/view/viewOverlays.ts @@ -14,6 +14,8 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class ViewOverlays extends ViewPart implements IVisibleLinesHost { @@ -147,7 +149,7 @@ export class ViewOverlayLine implements IVisibleLine { constructor(configuration: IConfiguration, dynamicOverlays: DynamicViewOverlay[]) { this._configuration = configuration; - this._lineHeight = this._configuration.editor.lineHeight; + this._lineHeight = this._configuration.options.get(EditorOption.lineHeight); this._dynamicOverlays = dynamicOverlays; this._domNode = null; @@ -171,9 +173,7 @@ export class ViewOverlayLine implements IVisibleLine { // Nothing } public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): void { - if (e.lineHeight) { - this._lineHeight = this._configuration.editor.lineHeight; - } + this._lineHeight = this._configuration.options.get(EditorOption.lineHeight); } public renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData, sb: IStringBuilder): boolean { @@ -215,8 +215,9 @@ export class ContentViewOverlays extends ViewOverlays { constructor(context: ViewContext) { super(context); - - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + this._contentWidth = layoutInfo.contentWidth; this.domNode.setHeight(0); } @@ -224,10 +225,10 @@ export class ContentViewOverlays extends ViewOverlays { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.layoutInfo) { - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; - } - return super.onConfigurationChanged(e); + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + this._contentWidth = layoutInfo.contentWidth; + return super.onConfigurationChanged(e) || true; } public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean { return super.onScrollChanged(e) || e.scrollWidthChanged; @@ -249,25 +250,22 @@ export class MarginViewOverlays extends ViewOverlays { constructor(context: ViewContext) { super(context); - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + this._contentLeft = layoutInfo.contentLeft; this.domNode.setClassName('margin-view-overlays'); this.domNode.setWidth(1); - Configuration.applyFontInfo(this.domNode, this._context.configuration.editor.fontInfo); + Configuration.applyFontInfo(this.domNode, options.get(EditorOption.fontInfo)); } public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - let shouldRender = false; - if (e.fontInfo) { - Configuration.applyFontInfo(this.domNode, this._context.configuration.editor.fontInfo); - shouldRender = true; - } - if (e.layoutInfo) { - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; - shouldRender = true; - } - return super.onConfigurationChanged(e) || shouldRender; + const options = this._context.configuration.options; + Configuration.applyFontInfo(this.domNode, options.get(EditorOption.fontInfo)); + const layoutInfo = options.get(EditorOption.layoutInfo); + this._contentLeft = layoutInfo.contentLeft; + return super.onConfigurationChanged(e) || true; } public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean { diff --git a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts index ca4c277539..dcba54f657 100644 --- a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts +++ b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts @@ -14,6 +14,8 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + class Coordinate { _coordinateBrand: void; @@ -207,10 +209,13 @@ class Widget { this.allowEditorOverflow = this._actual.allowEditorOverflow || false; this.suppressMouseDown = this._actual.suppressMouseDown || false; - this._fixedOverflowWidgets = this._context.configuration.editor.viewInfo.fixedOverflowWidgets; - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; - this._lineHeight = this._context.configuration.editor.lineHeight; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._fixedOverflowWidgets = options.get(EditorOption.fixedOverflowWidgets); + this._contentWidth = layoutInfo.contentWidth; + this._contentLeft = layoutInfo.contentLeft; + this._lineHeight = options.get(EditorOption.lineHeight); this._position = null; this._range = null; @@ -230,12 +235,12 @@ class Widget { } public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): void { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.layoutInfo) { - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; + const options = this._context.configuration.options; + this._lineHeight = options.get(EditorOption.lineHeight); + if (e.hasChanged(EditorOption.layoutInfo)) { + const layoutInfo = options.get(EditorOption.layoutInfo); + this._contentLeft = layoutInfo.contentLeft; + this._contentWidth = layoutInfo.contentWidth; this._maxWidth = this._getMaxWidth(); } } diff --git a/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts b/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts index 734a75e418..762d2cff11 100644 --- a/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts +++ b/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts @@ -10,26 +10,33 @@ import { RenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class CurrentLineHighlightOverlay extends DynamicViewOverlay { private readonly _context: ViewContext; private _lineHeight: number; private _renderLineHighlight: 'none' | 'gutter' | 'line' | 'all'; + private _contentWidth: number; private _selectionIsEmpty: boolean; private _primaryCursorLineNumber: number; private _scrollWidth: number; - private _contentWidth: number; constructor(context: ViewContext) { super(); this._context = context; - this._lineHeight = this._context.configuration.editor.lineHeight; - this._renderLineHighlight = this._context.configuration.editor.viewInfo.renderLineHighlight; + + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._renderLineHighlight = options.get(EditorOption.renderLineHighlight); + this._contentWidth = layoutInfo.contentWidth; this._selectionIsEmpty = true; this._primaryCursorLineNumber = 1; this._scrollWidth = 0; - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; + this._context.addEventHandler(this); } @@ -42,15 +49,12 @@ export class CurrentLineHighlightOverlay extends DynamicViewOverlay { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.viewInfo) { - this._renderLineHighlight = this._context.configuration.editor.viewInfo.renderLineHighlight; - } - if (e.layoutInfo) { - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; - } + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._renderLineHighlight = options.get(EditorOption.renderLineHighlight); + this._contentWidth = layoutInfo.contentWidth; return true; } public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { diff --git a/src/vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight.ts b/src/vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight.ts index f471467f90..cd0aa2c9fa 100644 --- a/src/vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight.ts +++ b/src/vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight.ts @@ -10,24 +10,30 @@ import { RenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay { private readonly _context: ViewContext; private _lineHeight: number; private _renderLineHighlight: 'none' | 'gutter' | 'line' | 'all'; + private _contentLeft: number; private _selectionIsEmpty: boolean; private _primaryCursorLineNumber: number; - private _contentLeft: number; constructor(context: ViewContext) { super(); this._context = context; - this._lineHeight = this._context.configuration.editor.lineHeight; - this._renderLineHighlight = this._context.configuration.editor.viewInfo.renderLineHighlight; + + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._renderLineHighlight = options.get(EditorOption.renderLineHighlight); + this._contentLeft = layoutInfo.contentLeft; this._selectionIsEmpty = true; this._primaryCursorLineNumber = 1; - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; this._context.addEventHandler(this); } @@ -40,15 +46,12 @@ export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.viewInfo) { - this._renderLineHighlight = this._context.configuration.editor.viewInfo.renderLineHighlight; - } - if (e.layoutInfo) { - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; - } + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._renderLineHighlight = options.get(EditorOption.renderLineHighlight); + this._contentLeft = layoutInfo.contentLeft; return true; } public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { diff --git a/src/vs/editor/browser/viewParts/decorations/decorations.ts b/src/vs/editor/browser/viewParts/decorations/decorations.ts index 1c44aabdca..7baed2b6f0 100644 --- a/src/vs/editor/browser/viewParts/decorations/decorations.ts +++ b/src/vs/editor/browser/viewParts/decorations/decorations.ts @@ -10,6 +10,7 @@ import { HorizontalRange, RenderingContext } from 'vs/editor/common/view/renderi import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class DecorationsOverlay extends DynamicViewOverlay { @@ -21,8 +22,9 @@ export class DecorationsOverlay extends DynamicViewOverlay { constructor(context: ViewContext) { super(); this._context = context; - this._lineHeight = this._context.configuration.editor.lineHeight; - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; + const options = this._context.configuration.options; + this._lineHeight = options.get(EditorOption.lineHeight); + this._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; this._renderResult = null; this._context.addEventHandler(this); @@ -37,12 +39,9 @@ export class DecorationsOverlay extends DynamicViewOverlay { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.fontInfo) { - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; - } + const options = this._context.configuration.options; + this._lineHeight = options.get(EditorOption.lineHeight); + this._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; return true; } public onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean { diff --git a/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts b/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts index 06f25850ef..bcf29eb93b 100644 --- a/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts +++ b/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts @@ -14,6 +14,7 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { getThemeTypeSelector } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class EditorScrollbar extends ViewPart { @@ -28,8 +29,11 @@ export class EditorScrollbar extends ViewPart { ) { super(context); - const editor = this._context.configuration.editor; - const configScrollbarOpts = editor.viewInfo.scrollbar; + + const options = this._context.configuration.options; + const scrollbar = options.get(EditorOption.scrollbar); + const mouseWheelScrollSensitivity = options.get(EditorOption.mouseWheelScrollSensitivity); + const fastScrollSensitivity = options.get(EditorOption.fastScrollSensitivity); const scrollbarOptions: ScrollableElementCreationOptions = { listenOnDomNode: viewDomNode.domNode, @@ -37,18 +41,18 @@ export class EditorScrollbar extends ViewPart { useShadows: false, lazyRender: true, - vertical: configScrollbarOpts.vertical, - horizontal: configScrollbarOpts.horizontal, - verticalHasArrows: configScrollbarOpts.verticalHasArrows, - horizontalHasArrows: configScrollbarOpts.horizontalHasArrows, - verticalScrollbarSize: configScrollbarOpts.verticalScrollbarSize, - verticalSliderSize: configScrollbarOpts.verticalSliderSize, - horizontalScrollbarSize: configScrollbarOpts.horizontalScrollbarSize, - horizontalSliderSize: configScrollbarOpts.horizontalSliderSize, - handleMouseWheel: configScrollbarOpts.handleMouseWheel, - arrowSize: configScrollbarOpts.arrowSize, - mouseWheelScrollSensitivity: configScrollbarOpts.mouseWheelScrollSensitivity, - fastScrollSensitivity: configScrollbarOpts.fastScrollSensitivity, + vertical: scrollbar.vertical, + horizontal: scrollbar.horizontal, + verticalHasArrows: scrollbar.verticalHasArrows, + horizontalHasArrows: scrollbar.horizontalHasArrows, + verticalScrollbarSize: scrollbar.verticalScrollbarSize, + verticalSliderSize: scrollbar.verticalSliderSize, + horizontalScrollbarSize: scrollbar.horizontalScrollbarSize, + horizontalSliderSize: scrollbar.horizontalSliderSize, + handleMouseWheel: scrollbar.handleMouseWheel, + arrowSize: scrollbar.arrowSize, + mouseWheelScrollSensitivity: mouseWheelScrollSensitivity, + fastScrollSensitivity: fastScrollSensitivity, }; this.scrollbar = this._register(new SmoothScrollableElement(linesContent.domNode, scrollbarOptions, this._context.viewLayout.scrollable)); @@ -96,11 +100,13 @@ export class EditorScrollbar extends ViewPart { } private _setLayout(): void { - const layoutInfo = this._context.configuration.editor.layoutInfo; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); this.scrollbarDomNode.setLeft(layoutInfo.contentLeft); - const side = this._context.configuration.editor.viewInfo.minimap.side; + const minimap = options.get(EditorOption.minimap); + const side = minimap.side; if (side === 'right') { this.scrollbarDomNode.setWidth(layoutInfo.contentWidth + layoutInfo.minimapWidth); } else { @@ -124,16 +130,23 @@ export class EditorScrollbar extends ViewPart { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.viewInfo) { - const editor = this._context.configuration.editor; + if ( + e.hasChanged(EditorOption.scrollbar) + || e.hasChanged(EditorOption.mouseWheelScrollSensitivity) + || e.hasChanged(EditorOption.fastScrollSensitivity) + ) { + const options = this._context.configuration.options; + const scrollbar = options.get(EditorOption.scrollbar); + const mouseWheelScrollSensitivity = options.get(EditorOption.mouseWheelScrollSensitivity); + const fastScrollSensitivity = options.get(EditorOption.fastScrollSensitivity); const newOpts: ScrollableElementChangeOptions = { - handleMouseWheel: editor.viewInfo.scrollbar.handleMouseWheel, - mouseWheelScrollSensitivity: editor.viewInfo.scrollbar.mouseWheelScrollSensitivity, - fastScrollSensitivity: editor.viewInfo.scrollbar.fastScrollSensitivity + handleMouseWheel: scrollbar.handleMouseWheel, + mouseWheelScrollSensitivity: mouseWheelScrollSensitivity, + fastScrollSensitivity: fastScrollSensitivity }; this.scrollbar.updateOptions(newOpts); } - if (e.layoutInfo) { + if (e.hasChanged(EditorOption.layoutInfo)) { this._setLayout(); } return true; diff --git a/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts b/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts index 43a4a8a826..4b25021a9e 100644 --- a/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts +++ b/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts @@ -8,6 +8,8 @@ import { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay'; import { RenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class DecorationToRender { _decorationToRenderBrand: void; @@ -84,10 +86,14 @@ export class GlyphMarginOverlay extends DedupOverlay { constructor(context: ViewContext) { super(); this._context = context; - this._lineHeight = this._context.configuration.editor.lineHeight; - this._glyphMargin = this._context.configuration.editor.viewInfo.glyphMargin; - this._glyphMarginLeft = this._context.configuration.editor.layoutInfo.glyphMarginLeft; - this._glyphMarginWidth = this._context.configuration.editor.layoutInfo.glyphMarginWidth; + + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._glyphMargin = options.get(EditorOption.glyphMargin); + this._glyphMarginLeft = layoutInfo.glyphMarginLeft; + this._glyphMarginWidth = layoutInfo.glyphMarginWidth; this._renderResult = null; this._context.addEventHandler(this); } @@ -101,16 +107,13 @@ export class GlyphMarginOverlay extends DedupOverlay { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.viewInfo) { - this._glyphMargin = this._context.configuration.editor.viewInfo.glyphMargin; - } - if (e.layoutInfo) { - this._glyphMarginLeft = this._context.configuration.editor.layoutInfo.glyphMarginLeft; - this._glyphMarginWidth = this._context.configuration.editor.layoutInfo.glyphMarginWidth; - } + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._glyphMargin = options.get(EditorOption.glyphMargin); + this._glyphMarginLeft = layoutInfo.glyphMarginLeft; + this._glyphMarginWidth = layoutInfo.glyphMarginWidth; return true; } public onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean { diff --git a/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts b/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts index 965c859a69..84f35e0f20 100644 --- a/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts +++ b/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts @@ -11,6 +11,8 @@ import { RenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class IndentGuidesOverlay extends DynamicViewOverlay { @@ -27,12 +29,16 @@ export class IndentGuidesOverlay extends DynamicViewOverlay { super(); this._context = context; this._primaryLineNumber = 0; - this._lineHeight = this._context.configuration.editor.lineHeight; - this._spaceWidth = this._context.configuration.editor.fontInfo.spaceWidth; - this._enabled = this._context.configuration.editor.viewInfo.renderIndentGuides; - this._activeIndentEnabled = this._context.configuration.editor.viewInfo.highlightActiveIndentGuide; - const wrappingColumn = this._context.configuration.editor.wrappingInfo.wrappingColumn; - this._maxIndentLeft = wrappingColumn === -1 ? -1 : (wrappingColumn * this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth); + + const options = this._context.configuration.options; + const wrappingInfo = options.get(EditorOption.wrappingInfo); + const fontInfo = options.get(EditorOption.fontInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._spaceWidth = fontInfo.spaceWidth; + this._enabled = options.get(EditorOption.renderIndentGuides); + this._activeIndentEnabled = options.get(EditorOption.highlightActiveIndentGuide); + this._maxIndentLeft = wrappingInfo.wrappingColumn === -1 ? -1 : (wrappingInfo.wrappingColumn * fontInfo.typicalHalfwidthCharacterWidth); this._renderResult = null; @@ -48,20 +54,15 @@ export class IndentGuidesOverlay extends DynamicViewOverlay { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.fontInfo) { - this._spaceWidth = this._context.configuration.editor.fontInfo.spaceWidth; - } - if (e.viewInfo) { - this._enabled = this._context.configuration.editor.viewInfo.renderIndentGuides; - this._activeIndentEnabled = this._context.configuration.editor.viewInfo.highlightActiveIndentGuide; - } - if (e.wrappingInfo || e.fontInfo) { - const wrappingColumn = this._context.configuration.editor.wrappingInfo.wrappingColumn; - this._maxIndentLeft = wrappingColumn === -1 ? -1 : (wrappingColumn * this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth); - } + const options = this._context.configuration.options; + const wrappingInfo = options.get(EditorOption.wrappingInfo); + const fontInfo = options.get(EditorOption.fontInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._spaceWidth = fontInfo.spaceWidth; + this._enabled = options.get(EditorOption.renderIndentGuides); + this._activeIndentEnabled = options.get(EditorOption.highlightActiveIndentGuide); + this._maxIndentLeft = wrappingInfo.wrappingColumn === -1 ? -1 : (wrappingInfo.wrappingColumn * fontInfo.typicalHalfwidthCharacterWidth); return true; } public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { diff --git a/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts b/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts index 6797ddf55e..b3dd48afd5 100644 --- a/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts +++ b/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts @@ -6,7 +6,7 @@ import 'vs/css!./lineNumbers'; import * as platform from 'vs/base/common/platform'; import { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay'; -import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions'; +import { RenderLineNumbersType, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { editorActiveLineNumber, editorLineNumbers } from 'vs/editor/common/view/editorColorRegistry'; import { RenderingContext } from 'vs/editor/common/view/renderingContext'; @@ -41,13 +41,15 @@ export class LineNumbersOverlay extends DynamicViewOverlay { } private _readConfig(): void { - const config = this._context.configuration.editor; - this._lineHeight = config.lineHeight; - this._renderLineNumbers = config.viewInfo.renderLineNumbers; - this._renderCustomLineNumbers = config.viewInfo.renderCustomLineNumbers; - this._renderFinalNewline = config.viewInfo.renderFinalNewline; - this._lineNumbersLeft = config.layoutInfo.lineNumbersLeft; - this._lineNumbersWidth = config.layoutInfo.lineNumbersWidth; + const options = this._context.configuration.options; + this._lineHeight = options.get(EditorOption.lineHeight); + const lineNumbers = options.get(EditorOption.lineNumbers); + this._renderLineNumbers = lineNumbers.renderType; + this._renderCustomLineNumbers = lineNumbers.renderFn; + this._renderFinalNewline = options.get(EditorOption.renderFinalNewline); + const layoutInfo = options.get(EditorOption.layoutInfo); + this._lineNumbersLeft = layoutInfo.lineNumbersLeft; + this._lineNumbersWidth = layoutInfo.lineNumbersWidth; } public dispose(): void { diff --git a/src/vs/editor/browser/viewParts/lines/viewLine.ts b/src/vs/editor/browser/viewParts/lines/viewLine.ts index 8cda798ee4..c8eba1d667 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLine.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLine.ts @@ -16,6 +16,7 @@ import { CharacterMapping, ForeignElementType, RenderLineInput, renderViewLine, import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel'; import { HIGH_CONTRAST, ThemeType } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const canUseFastRenderedViewLine = (function () { if (platform.isNative) { @@ -80,17 +81,20 @@ export class ViewLineOptions { constructor(config: IConfiguration, themeType: ThemeType) { this.themeType = themeType; - this.renderWhitespace = config.editor.viewInfo.renderWhitespace; - this.renderControlCharacters = config.editor.viewInfo.renderControlCharacters; - this.spaceWidth = config.editor.fontInfo.spaceWidth; + const options = config.options; + const fontInfo = options.get(EditorOption.fontInfo); + this.renderWhitespace = options.get(EditorOption.renderWhitespace); + this.renderControlCharacters = options.get(EditorOption.renderControlCharacters); + this.spaceWidth = fontInfo.spaceWidth; this.useMonospaceOptimizations = ( - config.editor.fontInfo.isMonospace - && !config.editor.viewInfo.disableMonospaceOptimizations + fontInfo.isMonospace + && !options.get(EditorOption.disableMonospaceOptimizations) + && !options.get(EditorOption.fontLigatures) ); - this.canUseHalfwidthRightwardsArrow = config.editor.fontInfo.canUseHalfwidthRightwardsArrow; - this.lineHeight = config.editor.lineHeight; - this.stopRenderingLineAfter = config.editor.viewInfo.stopRenderingLineAfter; - this.fontLigatures = config.editor.viewInfo.fontLigatures; + this.canUseHalfwidthRightwardsArrow = fontInfo.canUseHalfwidthRightwardsArrow; + this.lineHeight = options.get(EditorOption.lineHeight); + this.stopRenderingLineAfter = options.get(EditorOption.stopRenderingLineAfter); + this.fontLigatures = options.get(EditorOption.fontLigatures); } public equals(other: ViewLineOptions): boolean { diff --git a/src/vs/editor/browser/viewParts/lines/viewLines.ts b/src/vs/editor/browser/viewParts/lines/viewLines.ts index 72928a9fda..e30dbae238 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLines.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLines.ts @@ -12,12 +12,14 @@ import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/v import { DomReadingContext, ViewLine, ViewLineOptions } from 'vs/editor/browser/viewParts/lines/viewLine'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; +import { Selection } from 'vs/editor/common/core/selection'; import { ScrollType } from 'vs/editor/common/editorCommon'; import { HorizontalRange, IViewLines, LineVisibleRanges } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { Viewport } from 'vs/editor/common/viewModel/viewModel'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; class LastRenderedData { @@ -71,7 +73,8 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, private _typicalHalfwidthCharacterWidth: number; private _isViewportWrapping: boolean; private _revealHorizontalRightPadding: number; - private _scrollOff: number; + private _selections: Selection[]; + private _cursorSurroundingLines: number; private _canUseLayerHinting: boolean; private _viewLineOptions: ViewLineOptions; @@ -90,18 +93,22 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, this.domNode = this._visibleLines.domNode; const conf = this._context.configuration; + const options = this._context.configuration.options; + const fontInfo = options.get(EditorOption.fontInfo); + const wrappingInfo = options.get(EditorOption.wrappingInfo); - this._lineHeight = conf.editor.lineHeight; - this._typicalHalfwidthCharacterWidth = conf.editor.fontInfo.typicalHalfwidthCharacterWidth; - this._isViewportWrapping = conf.editor.wrappingInfo.isViewportWrapping; - this._revealHorizontalRightPadding = conf.editor.viewInfo.revealHorizontalRightPadding; - this._scrollOff = conf.editor.viewInfo.cursorSurroundingLines; - this._canUseLayerHinting = conf.editor.canUseLayerHinting; + this._lineHeight = options.get(EditorOption.lineHeight); + this._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; + this._isViewportWrapping = wrappingInfo.isViewportWrapping; + this._revealHorizontalRightPadding = options.get(EditorOption.revealHorizontalRightPadding); + this._cursorSurroundingLines = options.get(EditorOption.cursorSurroundingLines); + this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting); this._viewLineOptions = new ViewLineOptions(conf, this._context.theme.type); + this._selections = []; PartFingerprints.write(this.domNode, PartFingerprint.ViewLines); this.domNode.setClassName('view-lines'); - Configuration.applyFontInfo(this.domNode, conf.editor.fontInfo); + Configuration.applyFontInfo(this.domNode, fontInfo); // --- width & height this._maxLineWidth = 0; @@ -135,35 +142,25 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { this._visibleLines.onConfigurationChanged(e); - if (e.wrappingInfo) { + if (e.hasChanged(EditorOption.wrappingInfo)) { this._maxLineWidth = 0; } - const conf = this._context.configuration; + const options = this._context.configuration.options; + const fontInfo = options.get(EditorOption.fontInfo); + const wrappingInfo = options.get(EditorOption.wrappingInfo); - if (e.lineHeight) { - this._lineHeight = conf.editor.lineHeight; - } - if (e.fontInfo) { - this._typicalHalfwidthCharacterWidth = conf.editor.fontInfo.typicalHalfwidthCharacterWidth; - } - if (e.wrappingInfo) { - this._isViewportWrapping = conf.editor.wrappingInfo.isViewportWrapping; - } - if (e.viewInfo) { - this._revealHorizontalRightPadding = conf.editor.viewInfo.revealHorizontalRightPadding; - this._scrollOff = conf.editor.viewInfo.cursorSurroundingLines; - } - if (e.canUseLayerHinting) { - this._canUseLayerHinting = conf.editor.canUseLayerHinting; - } - if (e.fontInfo) { - Configuration.applyFontInfo(this.domNode, conf.editor.fontInfo); - } + this._lineHeight = options.get(EditorOption.lineHeight); + this._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; + this._isViewportWrapping = wrappingInfo.isViewportWrapping; + this._revealHorizontalRightPadding = options.get(EditorOption.revealHorizontalRightPadding); + this._cursorSurroundingLines = options.get(EditorOption.cursorSurroundingLines); + this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting); + Configuration.applyFontInfo(this.domNode, fontInfo); this._onOptionsMaybeChanged(); - if (e.layoutInfo) { + if (e.hasChanged(EditorOption.layoutInfo)) { this._maxLineWidth = 0; } @@ -188,6 +185,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, return false; } public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { + this._selections = e.selections; const rendStartLineNumber = this._visibleLines.getStartLineNumber(); const rendEndLineNumber = this._visibleLines.getEndLineNumber(); let r = false; @@ -223,7 +221,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, public onRevealRangeRequest(e: viewEvents.ViewRevealRangeRequestEvent): boolean { // Using the future viewport here in order to handle multiple // incoming reveal range requests that might all desire to be animated - const desiredScrollTop = this._computeScrollTopToRevealRange(this._context.viewLayout.getFutureViewport(), e.range, e.verticalType); + const desiredScrollTop = this._computeScrollTopToRevealRange(this._context.viewLayout.getFutureViewport(), e.source, e.range, e.verticalType); // validate the new desired scroll top let newScrollPosition = this._context.viewLayout.validateScrollPosition({ scrollTop: desiredScrollTop }); @@ -589,7 +587,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, } } - private _computeScrollTopToRevealRange(viewport: Viewport, range: Range, verticalType: viewEvents.VerticalRevealType): number { + private _computeScrollTopToRevealRange(viewport: Viewport, source: string, range: Range, verticalType: viewEvents.VerticalRevealType): number { const viewportStartY = viewport.top; const viewportHeight = viewport.height; const viewportEndY = viewportStartY + viewportHeight; @@ -600,9 +598,16 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, boxStartY = this._context.viewLayout.getVerticalOffsetForLineNumber(range.startLineNumber); boxEndY = this._context.viewLayout.getVerticalOffsetForLineNumber(range.endLineNumber) + this._lineHeight; - const context = Math.min((viewportHeight / this._lineHeight) / 2, this._scrollOff); - boxStartY -= context * this._lineHeight; - boxEndY += Math.max(0, (context - 1)) * this._lineHeight; + const shouldIgnoreScrollOff = source === 'mouse' && ( + this._selections.length > 1 // scroll off might trigger scrolling and mess up with multi cursor + || (this._selections.length > 0 && this._selections[0].isEmpty()) // we don't want to single click triggering selection + ); + + if (!shouldIgnoreScrollOff) { + const context = Math.min((viewportHeight / this._lineHeight) / 2, this._cursorSurroundingLines); + boxStartY -= context * this._lineHeight; + boxEndY += Math.max(0, (context - 1)) * this._lineHeight; + } if (verticalType === viewEvents.VerticalRevealType.Simple || verticalType === viewEvents.VerticalRevealType.Bottom) { // Reveal one line more when the last line would be covered by the scrollbar - arrow down case or revealing a line explicitly at bottom diff --git a/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts b/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts index 2398b61155..c46c904c66 100644 --- a/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts +++ b/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts @@ -8,6 +8,8 @@ import { DecorationToRender, DedupOverlay } from 'vs/editor/browser/viewParts/gl import { RenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class LinesDecorationsOverlay extends DedupOverlay { @@ -20,8 +22,10 @@ export class LinesDecorationsOverlay extends DedupOverlay { constructor(context: ViewContext) { super(); this._context = context; - this._decorationsLeft = this._context.configuration.editor.layoutInfo.decorationsLeft; - this._decorationsWidth = this._context.configuration.editor.layoutInfo.decorationsWidth; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + this._decorationsLeft = layoutInfo.decorationsLeft; + this._decorationsWidth = layoutInfo.decorationsWidth; this._renderResult = null; this._context.addEventHandler(this); } @@ -35,10 +39,10 @@ export class LinesDecorationsOverlay extends DedupOverlay { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.layoutInfo) { - this._decorationsLeft = this._context.configuration.editor.layoutInfo.decorationsLeft; - this._decorationsWidth = this._context.configuration.editor.layoutInfo.decorationsWidth; - } + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + this._decorationsLeft = layoutInfo.decorationsLeft; + this._decorationsWidth = layoutInfo.decorationsWidth; return true; } public onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean { @@ -107,4 +111,4 @@ export class LinesDecorationsOverlay extends DedupOverlay { } return this._renderResult[lineNumber - startLineNumber]; } -} \ No newline at end of file +} diff --git a/src/vs/editor/browser/viewParts/margin/margin.ts b/src/vs/editor/browser/viewParts/margin/margin.ts index 6abfb30584..b55687e3b1 100644 --- a/src/vs/editor/browser/viewParts/margin/margin.ts +++ b/src/vs/editor/browser/viewParts/margin/margin.ts @@ -8,6 +8,8 @@ import { ViewPart } from 'vs/editor/browser/view/viewPart'; import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class Margin extends ViewPart { @@ -23,10 +25,13 @@ export class Margin extends ViewPart { constructor(context: ViewContext) { super(context); - this._canUseLayerHinting = this._context.configuration.editor.canUseLayerHinting; - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; - this._glyphMarginLeft = this._context.configuration.editor.layoutInfo.glyphMarginLeft; - this._glyphMarginWidth = this._context.configuration.editor.layoutInfo.glyphMarginWidth; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting); + this._contentLeft = layoutInfo.contentLeft; + this._glyphMarginLeft = layoutInfo.glyphMarginLeft; + this._glyphMarginWidth = layoutInfo.glyphMarginWidth; this._domNode = createFastDomNode(document.createElement('div')); this._domNode.setClassName(Margin.OUTER_CLASS_NAME); @@ -51,15 +56,13 @@ export class Margin extends ViewPart { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.canUseLayerHinting) { - this._canUseLayerHinting = this._context.configuration.editor.canUseLayerHinting; - } + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); - if (e.layoutInfo) { - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; - this._glyphMarginLeft = this._context.configuration.editor.layoutInfo.glyphMarginLeft; - this._glyphMarginWidth = this._context.configuration.editor.layoutInfo.glyphMarginWidth; - } + this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting); + this._contentLeft = layoutInfo.contentLeft; + this._glyphMarginLeft = layoutInfo.glyphMarginLeft; + this._glyphMarginWidth = layoutInfo.glyphMarginWidth; return true; } diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 71e926f5ff..5dc1565d40 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -13,7 +13,7 @@ import * as platform from 'vs/base/common/platform'; import * as strings from 'vs/base/common/strings'; import { ILine, RenderedLinesCollection } from 'vs/editor/browser/view/viewLayer'; import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart'; -import { RenderMinimap } from 'vs/editor/common/config/editorOptions'; +import { RenderMinimap, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Range } from 'vs/editor/common/core/range'; import { RGBA8 } from 'vs/editor/common/core/rgba'; import { IConfiguration, ScrollType } from 'vs/editor/common/editorCommon'; @@ -23,10 +23,12 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v import { getOrCreateMinimapCharRenderer } from 'vs/editor/common/view/runtimeMinimapCharRenderer'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; -import { ViewLineData, ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel'; -import { scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground } from 'vs/platform/theme/common/colorRegistry'; +import { ViewLineData } from 'vs/editor/common/viewModel/viewModel'; +import { scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, minimapSelection } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel'; +import { Selection } from 'vs/editor/common/core/selection'; +import { Color } from 'vs/base/common/color'; function getMinimapLineHeight(renderMinimap: RenderMinimap): number { if (renderMinimap === RenderMinimap.Large) { @@ -107,17 +109,18 @@ class MinimapOptions { public readonly canvasOuterHeight: number; constructor(configuration: IConfiguration) { - const pixelRatio = configuration.editor.pixelRatio; - const layoutInfo = configuration.editor.layoutInfo; - const viewInfo = configuration.editor.viewInfo; - const fontInfo = configuration.editor.fontInfo; + const options = configuration.options; + const pixelRatio = options.get(EditorOption.pixelRatio); + const layoutInfo = options.get(EditorOption.layoutInfo); + const fontInfo = options.get(EditorOption.fontInfo); this.renderMinimap = layoutInfo.renderMinimap | 0; - this.scrollBeyondLastLine = viewInfo.scrollBeyondLastLine; - this.showSlider = viewInfo.minimap.showSlider; + this.scrollBeyondLastLine = options.get(EditorOption.scrollBeyondLastLine); + const minimapOpts = options.get(EditorOption.minimap); + this.showSlider = minimapOpts.showSlider; this.pixelRatio = pixelRatio; this.typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; - this.lineHeight = configuration.editor.lineHeight; + this.lineHeight = options.get(EditorOption.lineHeight); this.minimapLeft = layoutInfo.minimapLeft; this.minimapWidth = layoutInfo.minimapWidth; this.minimapHeight = layoutInfo.height; @@ -451,7 +454,8 @@ export class Minimap extends ViewPart { private _options: MinimapOptions; private _lastRenderData: RenderData | null; - private _lastDecorations: ViewModelDecoration[] | undefined; + private _selections: Selection[] = []; + private _selectionColor: Color | undefined; private _renderDecorations: boolean = false; private _buffers: MinimapBuffers | null; @@ -461,6 +465,7 @@ export class Minimap extends ViewPart { this._options = new MinimapOptions(this._context.configuration); this._lastRenderData = null; this._buffers = null; + this._selectionColor = this._context.theme.getColor(minimapSelection); this._domNode = createFastDomNode(document.createElement('div')); PartFingerprints.write(this._domNode, PartFingerprint.Minimap); @@ -517,6 +522,7 @@ export class Minimap extends ViewPart { lineNumber = Math.min(lineNumber, this._context.model.getLineCount()); this._context.privateViewEventBus.emit(new viewEvents.ViewRevealRangeRequestEvent( + 'mouse', new Range(lineNumber, 1, lineNumber, 1), viewEvents.VerticalRevealType.Center, false, @@ -629,6 +635,11 @@ export class Minimap extends ViewPart { public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { return this._onOptionsMaybeChanged(); } + public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { + this._selections = e.selections; + this._renderDecorations = true; + return true; + } public onFlushed(e: viewEvents.ViewFlushedEvent): boolean { this._lastRenderData = null; return true; @@ -678,9 +689,9 @@ export class Minimap extends ViewPart { public onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean { this._context.model.invalidateMinimapColorCache(); - // Only bother calling render if decorations are currently shown - this._renderDecorations = !!this._lastDecorations; - return !!this._lastDecorations; + this._selectionColor = this._context.theme.getColor(minimapSelection); + this._renderDecorations = true; + return true; } // --- end event handlers @@ -742,8 +753,16 @@ export class Minimap extends ViewPart { canvasContext.clearRect(0, 0, canvasInnerWidth, canvasInnerHeight); - // Loop over decorations, ignoring those that don't have the minimap property set and rendering rectangles for each line the decoration spans const lineOffsetMap = new Map(); + for (let i = 0; i < this._selections.length; i++) { + const selection = this._selections[i]; + + for (let line = selection.startLineNumber; line <= selection.endLineNumber; line++) { + this.renderDecorationOnLine(canvasContext, lineOffsetMap, selection, this._selectionColor, layout, line, lineHeight, lineHeight, tabSize, characterWidth); + } + } + + // Loop over decorations, ignoring those that don't have the minimap property set and rendering rectangles for each line the decoration spans for (let i = 0; i < decorations.length; i++) { const decoration = decorations[i]; @@ -752,17 +771,17 @@ export class Minimap extends ViewPart { } for (let line = decoration.range.startLineNumber; line <= decoration.range.endLineNumber; line++) { - this.renderDecorationOnLine(canvasContext, lineOffsetMap, decoration, layout, line, lineHeight, lineHeight, tabSize, characterWidth); + const decorationColor = (decoration.options.minimap).getColor(this._context.theme); + this.renderDecorationOnLine(canvasContext, lineOffsetMap, decoration.range, decorationColor, layout, line, lineHeight, lineHeight, tabSize, characterWidth); } } - - this._lastDecorations = decorations; } } private renderDecorationOnLine(canvasContext: CanvasRenderingContext2D, lineOffsetMap: Map, - decoration: ViewModelDecoration, + decorationRange: Range, + decorationColor: Color | undefined, layout: MinimapLayout, lineNumber: number, height: number, @@ -791,7 +810,7 @@ export class Minimap extends ViewPart { lineOffsetMap.set(lineNumber, lineIndexToXOffset); } - const { startColumn, endColumn, startLineNumber, endLineNumber } = decoration.range; + const { startColumn, endColumn, startLineNumber, endLineNumber } = decorationRange; const x = startLineNumber === lineNumber ? lineIndexToXOffset[startColumn - 1] : 0; const endColumnForLine = endLineNumber > lineNumber ? lineIndexToXOffset.length - 1 : endColumn - 1; @@ -800,24 +819,21 @@ export class Minimap extends ViewPart { // If the decoration starts at the last character of the column and spans over it, ensure it has a width const width = lineIndexToXOffset[endColumnForLine] - x || 2; - this.renderDecoration(canvasContext, decoration.options.minimap, x, y, width, height); + this.renderDecoration(canvasContext, decorationColor, x, y, width, height); } if (isFirstDecorationForLine) { - this.renderLineHighlight(canvasContext, decoration.options.minimap, y, height); + this.renderLineHighlight(canvasContext, decorationColor, y, height); } } - private renderLineHighlight(canvasContext: CanvasRenderingContext2D, minimapOptions: ModelDecorationMinimapOptions, y: number, height: number): void { - const decorationColor = minimapOptions.getColor(this._context.theme); + private renderLineHighlight(canvasContext: CanvasRenderingContext2D, decorationColor: Color | undefined, y: number, height: number): void { canvasContext.fillStyle = decorationColor && decorationColor.transparent(0.5).toString() || ''; canvasContext.fillRect(0, y, canvasContext.canvas.width, height); } - private renderDecoration(canvasContext: CanvasRenderingContext2D, minimapOptions: ModelDecorationMinimapOptions, x: number, y: number, width: number, height: number) { - const decorationColor = minimapOptions.getColor(this._context.theme); - + private renderDecoration(canvasContext: CanvasRenderingContext2D, decorationColor: Color | undefined, x: number, y: number, width: number, height: number) { canvasContext.fillStyle = decorationColor && decorationColor.toString() || ''; canvasContext.fillRect(x, y, width, height); } diff --git a/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts b/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts index 18f46a26dd..241763520f 100644 --- a/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts +++ b/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts @@ -10,6 +10,8 @@ import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/v import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + interface IWidgetData { widget: IOverlayWidget; @@ -35,12 +37,15 @@ export class ViewOverlayWidgets extends ViewPart { constructor(context: ViewContext) { super(context); + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + this._widgets = {}; - this._verticalScrollbarWidth = this._context.configuration.editor.layoutInfo.verticalScrollbarWidth; - this._minimapWidth = this._context.configuration.editor.layoutInfo.minimapWidth; - this._horizontalScrollbarHeight = this._context.configuration.editor.layoutInfo.horizontalScrollbarHeight; - this._editorHeight = this._context.configuration.editor.layoutInfo.height; - this._editorWidth = this._context.configuration.editor.layoutInfo.width; + this._verticalScrollbarWidth = layoutInfo.verticalScrollbarWidth; + this._minimapWidth = layoutInfo.minimapWidth; + this._horizontalScrollbarHeight = layoutInfo.horizontalScrollbarHeight; + this._editorHeight = layoutInfo.height; + this._editorWidth = layoutInfo.width; this._domNode = createFastDomNode(document.createElement('div')); PartFingerprints.write(this._domNode, PartFingerprint.OverlayWidgets); @@ -59,15 +64,15 @@ export class ViewOverlayWidgets extends ViewPart { // ---- begin view event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.layoutInfo) { - this._verticalScrollbarWidth = this._context.configuration.editor.layoutInfo.verticalScrollbarWidth; - this._minimapWidth = this._context.configuration.editor.layoutInfo.minimapWidth; - this._horizontalScrollbarHeight = this._context.configuration.editor.layoutInfo.horizontalScrollbarHeight; - this._editorHeight = this._context.configuration.editor.layoutInfo.height; - this._editorWidth = this._context.configuration.editor.layoutInfo.width; - return true; - } - return false; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._verticalScrollbarWidth = layoutInfo.verticalScrollbarWidth; + this._minimapWidth = layoutInfo.minimapWidth; + this._horizontalScrollbarHeight = layoutInfo.horizontalScrollbarHeight; + this._editorHeight = layoutInfo.height; + this._editorWidth = layoutInfo.width; + return true; } // ---- end view event handlers diff --git a/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts b/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts index 024cec2cfc..f9f47e7c8d 100644 --- a/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts +++ b/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts @@ -15,6 +15,7 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ITheme } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; class Settings { @@ -42,22 +43,24 @@ class Settings { public readonly w: number[]; constructor(config: IConfiguration, theme: ITheme) { - this.lineHeight = config.editor.lineHeight; - this.pixelRatio = config.editor.pixelRatio; - this.overviewRulerLanes = config.editor.viewInfo.overviewRulerLanes; + const options = config.options; + this.lineHeight = options.get(EditorOption.lineHeight); + this.pixelRatio = options.get(EditorOption.pixelRatio); + this.overviewRulerLanes = options.get(EditorOption.overviewRulerLanes); - this.renderBorder = config.editor.viewInfo.overviewRulerBorder; + this.renderBorder = options.get(EditorOption.overviewRulerBorder); const borderColor = theme.getColor(editorOverviewRulerBorder); this.borderColor = borderColor ? borderColor.toString() : null; - this.hideCursor = config.editor.viewInfo.hideCursorInOverviewRuler; + this.hideCursor = options.get(EditorOption.hideCursorInOverviewRuler); const cursorColor = theme.getColor(editorCursorForeground); this.cursorColor = cursorColor ? cursorColor.transparent(0.7).toString() : null; this.themeType = theme.type; - const minimapEnabled = config.editor.viewInfo.minimap.enabled; - const minimapSide = config.editor.viewInfo.minimap.side; + const minimapOpts = options.get(EditorOption.minimap); + const minimapEnabled = minimapOpts.enabled; + const minimapSide = minimapOpts.side; const backgroundColor = (minimapEnabled ? TokenizationRegistry.getDefaultBackground() : null); if (backgroundColor === null || minimapSide === 'left') { this.backgroundColor = null; @@ -65,7 +68,8 @@ class Settings { this.backgroundColor = Color.Format.CSS.formatHex(backgroundColor); } - const position = config.editor.layoutInfo.overviewRuler; + const layoutInfo = options.get(EditorOption.layoutInfo); + const position = layoutInfo.overviewRuler; this.top = position.top; this.right = position.right; this.domWidth = position.width; diff --git a/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts b/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts index 1076832c7d..5d12d2ac3a 100644 --- a/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts +++ b/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts @@ -5,7 +5,7 @@ import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { IOverviewRuler } from 'vs/editor/browser/editorBrowser'; -import { OverviewRulerPosition } from 'vs/editor/common/config/editorOptions'; +import { OverviewRulerPosition, EditorOption } from 'vs/editor/common/config/editorOptions'; import { ColorZone, OverviewRulerZone, OverviewZoneManager } from 'vs/editor/common/view/overviewZoneManager'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; @@ -20,6 +20,7 @@ export class OverviewRuler extends ViewEventHandler implements IOverviewRuler { constructor(context: ViewContext, cssClassName: string) { super(); this._context = context; + const options = this._context.configuration.options; this._domNode = createFastDomNode(document.createElement('canvas')); this._domNode.setClassName(cssClassName); @@ -30,9 +31,9 @@ export class OverviewRuler extends ViewEventHandler implements IOverviewRuler { this._zoneManager.setDOMWidth(0); this._zoneManager.setDOMHeight(0); this._zoneManager.setOuterHeight(this._context.viewLayout.getScrollHeight()); - this._zoneManager.setLineHeight(this._context.configuration.editor.lineHeight); + this._zoneManager.setLineHeight(options.get(EditorOption.lineHeight)); - this._zoneManager.setPixelRatio(this._context.configuration.editor.pixelRatio); + this._zoneManager.setPixelRatio(options.get(EditorOption.pixelRatio)); this._context.addEventHandler(this); } @@ -45,13 +46,15 @@ export class OverviewRuler extends ViewEventHandler implements IOverviewRuler { // ---- begin view event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._zoneManager.setLineHeight(this._context.configuration.editor.lineHeight); + const options = this._context.configuration.options; + + if (e.hasChanged(EditorOption.lineHeight)) { + this._zoneManager.setLineHeight(options.get(EditorOption.lineHeight)); this._render(); } - if (e.pixelRatio) { - this._zoneManager.setPixelRatio(this._context.configuration.editor.pixelRatio); + if (e.hasChanged(EditorOption.pixelRatio)) { + this._zoneManager.setPixelRatio(options.get(EditorOption.pixelRatio)); this._domNode.setWidth(this._zoneManager.getDOMWidth()); this._domNode.setHeight(this._zoneManager.getDOMHeight()); this._domNode.domNode.width = this._zoneManager.getCanvasWidth(); diff --git a/src/vs/editor/browser/viewParts/rulers/rulers.ts b/src/vs/editor/browser/viewParts/rulers/rulers.ts index f0d24bc82e..08fe9ec92c 100644 --- a/src/vs/editor/browser/viewParts/rulers/rulers.ts +++ b/src/vs/editor/browser/viewParts/rulers/rulers.ts @@ -11,6 +11,7 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class Rulers extends ViewPart { @@ -26,8 +27,9 @@ export class Rulers extends ViewPart { this.domNode.setAttribute('aria-hidden', 'true'); this.domNode.setClassName('view-rulers'); this._renderedRulers = []; - this._rulers = this._context.configuration.editor.viewInfo.rulers; - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; + const options = this._context.configuration.options; + this._rulers = options.get(EditorOption.rulers); + this._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; } public dispose(): void { @@ -37,12 +39,10 @@ export class Rulers extends ViewPart { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.viewInfo || e.layoutInfo || e.fontInfo) { - this._rulers = this._context.configuration.editor.viewInfo.rulers; - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; - return true; - } - return false; + const options = this._context.configuration.options; + this._rulers = options.get(EditorOption.rulers); + this._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; + return true; } public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean { return e.scrollHeightChanged; diff --git a/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts b/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts index 7b496da70f..3fbcda8b19 100644 --- a/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts +++ b/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts @@ -11,6 +11,8 @@ import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { scrollbarShadow } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class ScrollDecorationViewPart extends ViewPart { @@ -27,7 +29,9 @@ export class ScrollDecorationViewPart extends ViewPart { this._width = 0; this._updateWidth(); this._shouldShow = false; - this._useShadows = this._context.configuration.editor.viewInfo.scrollbar.useShadows; + const options = this._context.configuration.options; + const scrollbar = options.get(EditorOption.scrollbar); + this._useShadows = scrollbar.useShadows; this._domNode = createFastDomNode(document.createElement('div')); this._domNode.setAttribute('role', 'presentation'); this._domNode.setAttribute('aria-hidden', 'true'); @@ -50,32 +54,26 @@ export class ScrollDecorationViewPart extends ViewPart { return this._domNode; } - private _updateWidth(): boolean { - const layoutInfo = this._context.configuration.editor.layoutInfo; - let newWidth = 0; + private _updateWidth(): void { + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + if (layoutInfo.renderMinimap === 0 || (layoutInfo.minimapWidth > 0 && layoutInfo.minimapLeft === 0)) { - newWidth = layoutInfo.width; + this._width = layoutInfo.width; } else { - newWidth = layoutInfo.width - layoutInfo.minimapWidth - layoutInfo.verticalScrollbarWidth; + this._width = layoutInfo.width - layoutInfo.minimapWidth - layoutInfo.verticalScrollbarWidth; } - if (this._width !== newWidth) { - this._width = newWidth; - return true; - } - return false; } // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - let shouldRender = false; - if (e.viewInfo) { - this._useShadows = this._context.configuration.editor.viewInfo.scrollbar.useShadows; - } - if (e.layoutInfo) { - shouldRender = this._updateWidth(); - } - return this._updateShouldShow() || shouldRender; + const options = this._context.configuration.options; + const scrollbar = options.get(EditorOption.scrollbar); + this._useShadows = scrollbar.useShadows; + this._updateWidth(); + this._updateShouldShow(); + return true; } public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean { this._scrollTop = e.scrollTop; @@ -99,4 +97,4 @@ registerThemingParticipant((theme, collector) => { if (shadow) { collector.addRule(`.monaco-editor .scroll-decoration { box-shadow: ${shadow} 0 6px 6px -6px inset; }`); } -}); \ No newline at end of file +}); diff --git a/src/vs/editor/browser/viewParts/selections/selections.ts b/src/vs/editor/browser/viewParts/selections/selections.ts index cf52b8c68d..162e90fe19 100644 --- a/src/vs/editor/browser/viewParts/selections/selections.ts +++ b/src/vs/editor/browser/viewParts/selections/selections.ts @@ -12,6 +12,7 @@ import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { editorInactiveSelection, editorSelectionBackground, editorSelectionForeground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const enum CornerStyle { EXTERN, @@ -83,9 +84,10 @@ export class SelectionsOverlay extends DynamicViewOverlay { constructor(context: ViewContext) { super(); this._context = context; - this._lineHeight = this._context.configuration.editor.lineHeight; - this._roundedSelection = this._context.configuration.editor.viewInfo.roundedSelection; - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; + const options = this._context.configuration.options; + this._lineHeight = options.get(EditorOption.lineHeight); + this._roundedSelection = options.get(EditorOption.roundedSelection); + this._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; this._selections = []; this._renderResult = null; this._context.addEventHandler(this); @@ -100,15 +102,10 @@ export class SelectionsOverlay extends DynamicViewOverlay { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.viewInfo) { - this._roundedSelection = this._context.configuration.editor.viewInfo.roundedSelection; - } - if (e.fontInfo) { - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; - } + const options = this._context.configuration.options; + this._lineHeight = options.get(EditorOption.lineHeight); + this._roundedSelection = options.get(EditorOption.roundedSelection); + this._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; return true; } public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { @@ -420,4 +417,4 @@ registerThemingParticipant((theme, collector) => { function abs(n: number): number { return n < 0 ? -n : n; -} \ No newline at end of file +} diff --git a/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts b/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts index a16a6ab6fb..ba55ed943a 100644 --- a/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts +++ b/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts @@ -7,7 +7,7 @@ import * as dom from 'vs/base/browser/dom'; import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import * as strings from 'vs/base/common/strings'; import { Configuration } from 'vs/editor/browser/config/configuration'; -import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions'; +import { TextEditorCursorStyle, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; @@ -51,11 +51,13 @@ export class ViewCursor { constructor(context: ViewContext) { this._context = context; + const options = this._context.configuration.options; + const fontInfo = options.get(EditorOption.fontInfo); - this._cursorStyle = this._context.configuration.editor.viewInfo.cursorStyle; - this._lineHeight = this._context.configuration.editor.lineHeight; - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; - this._lineCursorWidth = Math.min(this._context.configuration.editor.viewInfo.cursorWidth, this._typicalHalfwidthCharacterWidth); + this._cursorStyle = options.get(EditorOption.cursorStyle); + this._lineHeight = options.get(EditorOption.lineHeight); + this._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; + this._lineCursorWidth = Math.min(options.get(EditorOption.cursorWidth), this._typicalHalfwidthCharacterWidth); this._isVisible = true; @@ -65,7 +67,7 @@ export class ViewCursor { this._domNode.setHeight(this._lineHeight); this._domNode.setTop(0); this._domNode.setLeft(0); - Configuration.applyFontInfo(this._domNode, this._context.configuration.editor.fontInfo); + Configuration.applyFontInfo(this._domNode, fontInfo); this._domNode.setDisplay('none'); this._position = new Position(1, 1); @@ -97,17 +99,14 @@ export class ViewCursor { } public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.fontInfo) { - Configuration.applyFontInfo(this._domNode, this._context.configuration.editor.fontInfo); - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; - } - if (e.viewInfo) { - this._cursorStyle = this._context.configuration.editor.viewInfo.cursorStyle; - this._lineCursorWidth = Math.min(this._context.configuration.editor.viewInfo.cursorWidth, this._typicalHalfwidthCharacterWidth); - } + const options = this._context.configuration.options; + const fontInfo = options.get(EditorOption.fontInfo); + + this._cursorStyle = options.get(EditorOption.cursorStyle); + this._lineHeight = options.get(EditorOption.lineHeight); + this._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; + this._lineCursorWidth = Math.min(options.get(EditorOption.cursorWidth), this._typicalHalfwidthCharacterWidth); + Configuration.applyFontInfo(this._domNode, fontInfo); return true; } diff --git a/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts b/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts index 529d84eba4..1c38dcc7e7 100644 --- a/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts +++ b/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts @@ -8,7 +8,7 @@ import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { IntervalTimer, TimeoutTimer } from 'vs/base/common/async'; import { ViewPart } from 'vs/editor/browser/view/viewPart'; import { IViewCursorRenderData, ViewCursor } from 'vs/editor/browser/viewParts/viewCursors/viewCursor'; -import { TextEditorCursorBlinkingStyle, TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions'; +import { TextEditorCursorBlinkingStyle, TextEditorCursorStyle, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { editorCursorBackground, editorCursorForeground } from 'vs/editor/common/view/editorColorRegistry'; import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; @@ -43,10 +43,11 @@ export class ViewCursors extends ViewPart { constructor(context: ViewContext) { super(context); - this._readOnly = this._context.configuration.editor.readOnly; - this._cursorBlinking = this._context.configuration.editor.viewInfo.cursorBlinking; - this._cursorStyle = this._context.configuration.editor.viewInfo.cursorStyle; - this._cursorSmoothCaretAnimation = this._context.configuration.editor.viewInfo.cursorSmoothCaretAnimation; + const options = this._context.configuration.options; + this._readOnly = options.get(EditorOption.readOnly); + this._cursorBlinking = options.get(EditorOption.cursorBlinking); + this._cursorStyle = options.get(EditorOption.cursorStyle); + this._cursorSmoothCaretAnimation = options.get(EditorOption.cursorSmoothCaretAnimation); this._selectionIsEmpty = true; this._isVisible = false; @@ -84,21 +85,17 @@ export class ViewCursors extends ViewPart { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { + const options = this._context.configuration.options; - if (e.readOnly) { - this._readOnly = this._context.configuration.editor.readOnly; - } - if (e.viewInfo) { - this._cursorBlinking = this._context.configuration.editor.viewInfo.cursorBlinking; - this._cursorStyle = this._context.configuration.editor.viewInfo.cursorStyle; - this._cursorSmoothCaretAnimation = this._context.configuration.editor.viewInfo.cursorSmoothCaretAnimation; - } + this._readOnly = options.get(EditorOption.readOnly); + this._cursorBlinking = options.get(EditorOption.cursorBlinking); + this._cursorStyle = options.get(EditorOption.cursorStyle); + this._cursorSmoothCaretAnimation = options.get(EditorOption.cursorSmoothCaretAnimation); + + this._updateBlinking(); + this._updateDomClassName(); this._primaryCursor.onConfigurationChanged(e); - this._updateBlinking(); - if (e.viewInfo) { - this._updateDomClassName(); - } for (let i = 0, len = this._secondaryCursors.length; i < len; i++) { this._secondaryCursors[i].onConfigurationChanged(e); } diff --git a/src/vs/editor/browser/viewParts/viewZones/viewZones.ts b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts index 143a5a291c..feff29fc48 100644 --- a/src/vs/editor/browser/viewParts/viewZones/viewZones.ts +++ b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts @@ -12,6 +12,8 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewModel'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export interface IMyViewZone { whitespaceId: string; @@ -40,9 +42,12 @@ export class ViewZones extends ViewPart { constructor(context: ViewContext) { super(context); - this._lineHeight = this._context.configuration.editor.lineHeight; - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._contentWidth = layoutInfo.contentWidth; + this._contentLeft = layoutInfo.contentLeft; this.domNode = createFastDomNode(document.createElement('div')); this.domNode.setClassName('view-zones'); @@ -84,15 +89,15 @@ export class ViewZones extends ViewPart { } public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - return this._recomputeWhitespacesProps(); - } + this._lineHeight = options.get(EditorOption.lineHeight); + this._contentWidth = layoutInfo.contentWidth; + this._contentLeft = layoutInfo.contentLeft; - if (e.layoutInfo) { - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; + if (e.hasChanged(EditorOption.lineHeight)) { + this._recomputeWhitespacesProps(); } return true; diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 4cc249a04b..876b2cb5c9 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -23,7 +23,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService import { ICommandDelegate } from 'vs/editor/browser/view/viewController'; import { IContentWidgetData, IOverlayWidgetData, View } from 'vs/editor/browser/view/viewImpl'; import { ViewOutgoingEvents } from 'vs/editor/browser/view/viewOutgoingEvents'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById } from 'vs/editor/common/config/editorOptions'; import { Cursor, CursorStateChangedEvent } from 'vs/editor/common/controller/cursor'; import { CursorColumns, ICursors } from 'vs/editor/common/controller/cursorCommon'; import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -125,8 +125,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE private readonly _onDidChangeModelDecorations: Emitter = this._register(new Emitter()); public readonly onDidChangeModelDecorations: Event = this._onDidChangeModelDecorations.event; - private readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); - public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; + private readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); + public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; protected readonly _onDidChangeModel: Emitter = this._register(new Emitter()); public readonly onDidChangeModel: Event = this._onDidChangeModel.event; @@ -140,8 +140,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE private readonly _onDidAttemptReadOnlyEdit: Emitter = this._register(new Emitter()); public readonly onDidAttemptReadOnlyEdit: Event = this._onDidAttemptReadOnlyEdit.event; - private readonly _onDidLayoutChange: Emitter = this._register(new Emitter()); - public readonly onDidLayoutChange: Event = this._onDidLayoutChange.event; + private readonly _onDidLayoutChange: Emitter = this._register(new Emitter()); + public readonly onDidLayoutChange: Event = this._onDidLayoutChange.event; private readonly _editorTextFocus: BooleanEventEmitter = this._register(new BooleanEventEmitter()); public readonly onDidFocusEditorText: Event = this._editorTextFocus.onDidChangeToTrue; @@ -236,7 +236,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE constructor( domElement: HTMLElement, - options: editorOptions.IEditorOptions, + options: IEditorOptions, codeEditorWidgetOptions: ICodeEditorWidgetOptions, @IInstantiationService instantiationService: IInstantiationService, @ICodeEditorService codeEditorService: ICodeEditorService, @@ -259,10 +259,12 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._register(this._configuration.onDidChange((e) => { this._onDidChangeConfiguration.fire(e); - if (e.layoutInfo) { - this._onDidLayoutChange.fire(this._configuration.editor.layoutInfo); + const options = this._configuration.options; + if (e.hasChanged(EditorOption.layoutInfo)) { + const layoutInfo = options.get(EditorOption.layoutInfo); + this._onDidLayoutChange.fire(layoutInfo); } - if (this._configuration.editor.showUnused) { + if (options.get(EditorOption.showUnused)) { this._domElement.classList.add(SHOW_UNUSED_ENABLED_CLASS); } else { this._domElement.classList.remove(SHOW_UNUSED_ENABLED_CLASS); @@ -327,7 +329,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._codeEditorService.addCodeEditor(this); } - protected _createConfiguration(options: editorOptions.IEditorOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration { + protected _createConfiguration(options: IEditorOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration { return new Configuration(this.isSimpleWidget, options, this._domElement, accessibilityService); } @@ -362,15 +364,19 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return this._instantiationService.invokeFunction(fn); } - public updateOptions(newOptions: editorOptions.IEditorOptions): void { + public updateOptions(newOptions: IEditorOptions): void { this._configuration.updateOptions(newOptions); } - public getConfiguration(): editorOptions.InternalEditorOptions { - return this._configuration.editor; + public getOptions(): IComputedEditorOptions { + return this._configuration.options; } - public getRawConfiguration(): editorOptions.IEditorOptions { + public getOption(id: T): FindComputedEditorOptionValueById { + return this._configuration.options.get(id); + } + + public getRawOptions(): IEditorOptions { return this._configuration.getRawOptions(); } @@ -526,7 +532,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE const validatedModelRange = this._modelData.model.validateRange(modelRange); const viewRange = this._modelData.viewModel.coordinatesConverter.convertModelRangeToViewRange(validatedModelRange); - this._modelData.cursor.emitCursorRevealRange(viewRange, verticalType, revealHorizontal, scrollType); + this._modelData.cursor.emitCursorRevealRange('api', viewRange, verticalType, revealHorizontal, scrollType); } public revealLine(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { @@ -972,7 +978,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE if (!this._modelData) { return false; } - if (this._configuration.editor.readOnly) { + if (this._configuration.options.get(EditorOption.readOnly)) { // read only editor => sorry! return false; } @@ -984,7 +990,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE if (!this._modelData) { return false; } - if (this._configuration.editor.readOnly) { + if (this._configuration.options.get(EditorOption.readOnly)) { // read only editor => sorry! return false; } @@ -1028,7 +1034,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE if (!this._modelData) { return null; } - return this._modelData.model.getLineDecorations(lineNumber, this._id, this._configuration.editor.readOnly); + return this._modelData.model.getLineDecorations(lineNumber, this._id, this._configuration.options.get(EditorOption.readOnly)); } public deltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[] { @@ -1119,8 +1125,10 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } } - public getLayoutInfo(): editorOptions.EditorLayoutInfo { - return this._configuration.editor.layoutInfo; + public getLayoutInfo(): EditorLayoutInfo { + const options = this._configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + return layoutInfo; } public createOverviewRuler(cssClassName: string): editorBrowser.IOverviewRuler | null { @@ -1164,7 +1172,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } public hasWidgetFocus(): boolean { - return this._focusTracker && this._focusTracker.hasFocus(); + return (this._editorWidgetFocus.getValue() === BooleanEventValue.True); } public addContentWidget(widget: editorBrowser.IContentWidget): void { @@ -1268,7 +1276,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } const position = this._modelData.model.validatePosition(rawPosition); - const layoutInfo = this._configuration.editor.layoutInfo; + const options = this._configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); const top = CodeEditorWidget._getVerticalOffsetForPosition(this._modelData, position.lineNumber, position.column) - this.getScrollTop(); const left = this._modelData.view.getOffsetForColumn(position.lineNumber, position.column) + layoutInfo.glyphMarginWidth + layoutInfo.lineNumbersWidth + layoutInfo.decorationsWidth - this.getScrollLeft(); @@ -1276,7 +1285,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return { top: top, left: left, - height: this._configuration.editor.lineHeight + height: options.get(EditorOption.lineHeight) }; } @@ -1295,7 +1304,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } public applyFontInfo(target: HTMLElement): void { - Configuration.applyFontInfoSlow(target, this._configuration.editor.fontInfo); + Configuration.applyFontInfoSlow(target, this._configuration.options.get(EditorOption.fontInfo)); } protected _attachModel(model: ITextModel | null): void { @@ -1539,6 +1548,10 @@ export class BooleanEventEmitter extends Disposable { this._value = BooleanEventValue.NotSet; } + public getValue(): BooleanEventValue { + return this._value; + } + public setValue(_value: boolean) { const value = (_value ? BooleanEventValue.True : BooleanEventValue.False); if (this._value === value) { @@ -1601,10 +1614,10 @@ class EditorContextKeysManager extends Disposable { } private _updateFromConfig(): void { - const config = this._editor.getConfiguration(); + const options = this._editor.getOptions(); - this._editorTabMovesFocus.set(config.tabFocusMode); - this._editorReadonly.set(config.readOnly); + this._editorTabMovesFocus.set(options.get(EditorOption.tabFocusMode)); + this._editorReadonly.set(options.get(EditorOption.readOnly)); } private _updateFromSelection(): void { diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index def04ab469..b7f6e68d5a 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -20,7 +20,7 @@ import * as editorBrowser from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffReview } from 'vs/editor/browser/widget/diffReview'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { IDiffEditorOptions, IEditorOptions, EditorLayoutInfo, IComputedEditorOptions, EditorOption, EditorOptions } from 'vs/editor/common/config/editorOptions'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; @@ -81,7 +81,7 @@ class VisualEditorState { constructor( private _contextMenuService: IContextMenuService, - private _clipboardService: IClipboardService + private _clipboardService: IClipboardService | null ) { this._zones = []; this.inlineDiffMargins = []; @@ -131,7 +131,7 @@ class VisualEditorState { this._zones.push(zoneId); this._zonesMap[String(zoneId)] = true; - if (newDecorations.zones[i].diff && viewZone.marginDomNode) { + if (newDecorations.zones[i].diff && viewZone.marginDomNode && this._clipboardService) { this.inlineDiffMargins.push(new InlineDiffMargin(zoneId, viewZone.marginDomNode, editor, newDecorations.zones[i].diff!, this._contextMenuService, this._clipboardService)); } } @@ -212,12 +212,12 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE private readonly _notificationService: INotificationService; private readonly _reviewPane: DiffReview; - // {{SQL CARBON EDIT}} - private _options: editorOptions.IDiffEditorOptions; + private _options: IDiffEditorOptions; // {{SQL CARBON EDIT}} constructor( domElement: HTMLElement, - options: editorOptions.IDiffEditorOptions, + options: IDiffEditorOptions, + clipboardService: IClipboardService | null, @IEditorWorkerService editorWorkerService: IEditorWorkerService, @IContextKeyService contextKeyService: IContextKeyService, @IInstantiationService instantiationService: IInstantiationService, @@ -225,7 +225,6 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE @IThemeService themeService: IThemeService, @INotificationService notificationService: INotificationService, @IContextMenuService contextMenuService: IContextMenuService, - @IClipboardService clipboardService: IClipboardService ) { super(); @@ -235,8 +234,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE this._contextKeyService.createKey('isInDiffEditor', true); this._themeService = themeService; this._notificationService = notificationService; - // {{SQL CARBON EDIT}} - this._options = options; + + this._options = options; // {{SQL CARBON EDIT}} this.id = (++DIFF_EDITOR_ID); @@ -428,7 +427,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE this._layoutOverviewRulers(); } - private _createLeftHandSideEditor(options: editorOptions.IDiffEditorOptions, instantiationService: IInstantiationService): CodeEditorWidget { + private _createLeftHandSideEditor(options: IDiffEditorOptions, instantiationService: IInstantiationService): CodeEditorWidget { const editor = this._createInnerEditor(instantiationService, this._originalDomNode, this._adjustOptionsForLeftHandSide(options, this._originalIsEditable)); this._register(editor.onDidScrollChange((e) => { @@ -461,7 +460,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return editor; } - private _createRightHandSideEditor(options: editorOptions.IDiffEditorOptions, instantiationService: IInstantiationService): CodeEditorWidget { + private _createRightHandSideEditor(options: IDiffEditorOptions, instantiationService: IInstantiationService): CodeEditorWidget { const editor = this._createInnerEditor(instantiationService, this._modifiedDomNode, this._adjustOptionsForRightHandSide(options)); this._register(editor.onDidScrollChange((e) => { @@ -486,7 +485,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE })); this._register(editor.onDidChangeConfiguration((e) => { - if (e.fontInfo && editor.getModel()) { + if (e.hasChanged(EditorOption.fontInfo) && editor.getModel()) { this._onViewZonesChanged(); } })); @@ -500,7 +499,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return editor; } - protected _createInnerEditor(instantiationService: IInstantiationService, container: HTMLElement, options: editorOptions.IEditorOptions): CodeEditorWidget { + protected _createInnerEditor(instantiationService: IInstantiationService, container: HTMLElement, options: IEditorOptions): CodeEditorWidget { return instantiationService.createInstance(CodeEditorWidget, container, options, {}); } @@ -574,7 +573,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return this.modifiedEditor; } - public updateOptions(newOptions: editorOptions.IDiffEditorOptions): void { + public updateOptions(newOptions: IDiffEditorOptions): void { // Handle side by side let renderSideBySideChanged = false; @@ -974,8 +973,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE } } - private _adjustOptionsForSubEditor(options: editorOptions.IDiffEditorOptions): editorOptions.IDiffEditorOptions { - let clonedOptions: editorOptions.IDiffEditorOptions = objects.deepClone(options || {}); + private _adjustOptionsForSubEditor(options: IDiffEditorOptions): IDiffEditorOptions { + let clonedOptions: IDiffEditorOptions = objects.deepClone(options || {}); clonedOptions.inDiffEditor = true; clonedOptions.wordWrap = 'off'; clonedOptions.wordWrapMinified = false; @@ -993,7 +992,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return clonedOptions; } - private _adjustOptionsForLeftHandSide(options: editorOptions.IDiffEditorOptions, isEditable: boolean): editorOptions.IEditorOptions { + private _adjustOptionsForLeftHandSide(options: IDiffEditorOptions, isEditable: boolean): IEditorOptions { let result = this._adjustOptionsForSubEditor(options); result.readOnly = !isEditable; result.overviewRulerLanes = 1; @@ -1001,9 +1000,9 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return result; } - private _adjustOptionsForRightHandSide(options: editorOptions.IDiffEditorOptions): editorOptions.IEditorOptions { + private _adjustOptionsForRightHandSide(options: IDiffEditorOptions): IEditorOptions { let result = this._adjustOptionsForSubEditor(options); - result.revealHorizontalRightPadding = editorOptions.EDITOR_DEFAULTS.viewInfo.revealHorizontalRightPadding + DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH; + result.revealHorizontalRightPadding = EditorOptions.revealHorizontalRightPadding.defaultValue + DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH; result.scrollbar!.verticalHasArrows = false; result.extraEditorClassName = 'modified-in-monaco-diff-editor'; return result; @@ -1849,7 +1848,7 @@ class DiffEditorWidgetInline extends DiffEditorWidgetStyle implements IDiffEdito this.decorationsLeft = dataSource.getOriginalEditor().getLayoutInfo().decorationsLeft; - this._register(dataSource.getOriginalEditor().onDidLayoutChange((layoutInfo: editorOptions.EditorLayoutInfo) => { + this._register(dataSource.getOriginalEditor().onDidLayoutChange((layoutInfo: EditorLayoutInfo) => { if (this.decorationsLeft !== layoutInfo.decorationsLeft) { this.decorationsLeft = layoutInfo.decorationsLeft; dataSource.relayoutEditors(); @@ -1965,14 +1964,14 @@ class DiffEditorWidgetInline extends DiffEditorWidgetStyle implements IDiffEdito class InlineViewZonesComputer extends ViewZonesComputer { private readonly originalModel: ITextModel; - private readonly modifiedEditorConfiguration: editorOptions.InternalEditorOptions; + private readonly modifiedEditorOptions: IComputedEditorOptions; private readonly modifiedEditorTabSize: number; private readonly renderIndicators: boolean; constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean) { super(lineChanges, originalForeignVZ, modifiedForeignVZ); this.originalModel = originalEditor.getModel()!; - this.modifiedEditorConfiguration = modifiedEditor.getConfiguration(); + this.modifiedEditorOptions = modifiedEditor.getOptions(); this.modifiedEditorTabSize = modifiedEditor.getModel()!.getOptions().tabSize; this.renderIndicators = renderIndicators; } @@ -2012,13 +2011,16 @@ class InlineViewZonesComputer extends ViewZonesComputer { let sb = createStringBuilder(10000); let marginHTML: string[] = []; - let lineDecorationsWidth = this.modifiedEditorConfiguration.layoutInfo.decorationsWidth; - let lineHeight = this.modifiedEditorConfiguration.lineHeight; - const typicalHalfwidthCharacterWidth = this.modifiedEditorConfiguration.fontInfo.typicalHalfwidthCharacterWidth; + const layoutInfo = this.modifiedEditorOptions.get(EditorOption.layoutInfo); + const fontInfo = this.modifiedEditorOptions.get(EditorOption.fontInfo); + const lineDecorationsWidth = layoutInfo.decorationsWidth; + + let lineHeight = this.modifiedEditorOptions.get(EditorOption.lineHeight); + const typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; let maxCharsPerLine = 0; const originalContent: string[] = []; for (let lineNumber = lineChange.originalStartLineNumber; lineNumber <= lineChange.originalEndLineNumber; lineNumber++) { - maxCharsPerLine = Math.max(maxCharsPerLine, this._renderOriginalLine(lineNumber - lineChange.originalStartLineNumber, this.originalModel, this.modifiedEditorConfiguration, this.modifiedEditorTabSize, lineNumber, decorations, sb)); + maxCharsPerLine = Math.max(maxCharsPerLine, this._renderOriginalLine(lineNumber - lineChange.originalStartLineNumber, this.originalModel, this.modifiedEditorOptions, this.modifiedEditorTabSize, lineNumber, decorations, sb)); originalContent.push(this.originalModel.getLineContent(lineNumber)); if (this.renderIndicators) { @@ -2028,17 +2030,17 @@ class InlineViewZonesComputer extends ViewZonesComputer { ]); } } - maxCharsPerLine += this.modifiedEditorConfiguration.viewInfo.scrollBeyondLastColumn; + maxCharsPerLine += this.modifiedEditorOptions.get(EditorOption.scrollBeyondLastColumn); let domNode = document.createElement('div'); domNode.className = 'view-lines line-delete'; domNode.innerHTML = sb.build(); - Configuration.applyFontInfoSlow(domNode, this.modifiedEditorConfiguration.fontInfo); + Configuration.applyFontInfoSlow(domNode, fontInfo); let marginDomNode = document.createElement('div'); marginDomNode.className = 'inline-deleted-margin-view-zone'; marginDomNode.innerHTML = marginHTML.join(''); - Configuration.applyFontInfoSlow(marginDomNode, this.modifiedEditorConfiguration.fontInfo); + Configuration.applyFontInfoSlow(marginDomNode, fontInfo); return { shouldNotShrink: true, @@ -2057,9 +2059,10 @@ class InlineViewZonesComputer extends ViewZonesComputer { }; } - private _renderOriginalLine(count: number, originalModel: ITextModel, config: editorOptions.InternalEditorOptions, tabSize: number, lineNumber: number, decorations: InlineDecoration[], sb: IStringBuilder): number { + private _renderOriginalLine(count: number, originalModel: ITextModel, options: IComputedEditorOptions, tabSize: number, lineNumber: number, decorations: InlineDecoration[], sb: IStringBuilder): number { const lineTokens = originalModel.getLineTokens(lineNumber); const lineContent = lineTokens.getLineContent(); + const fontInfo = options.get(EditorOption.fontInfo); const actualDecorations = LineDecoration.filter(decorations, lineNumber, 1, lineContent.length + 1); @@ -2069,14 +2072,14 @@ class InlineViewZonesComputer extends ViewZonesComputer { sb.appendASCIIString(' char-delete'); } sb.appendASCIIString('" style="top:'); - sb.appendASCIIString(String(count * config.lineHeight)); + sb.appendASCIIString(String(count * options.get(EditorOption.lineHeight))); sb.appendASCIIString('px;width:1000000px;">'); const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, originalModel.mightContainNonBasicASCII()); const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, originalModel.mightContainRTL()); const output = renderViewLine(new RenderLineInput( - (config.fontInfo.isMonospace && !config.viewInfo.disableMonospaceOptimizations), - config.fontInfo.canUseHalfwidthRightwardsArrow, + (fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations) && !options.get(EditorOption.fontLigatures)), + fontInfo.canUseHalfwidthRightwardsArrow, lineContent, false, isBasicASCII, @@ -2085,11 +2088,11 @@ class InlineViewZonesComputer extends ViewZonesComputer { lineTokens, actualDecorations, tabSize, - config.fontInfo.spaceWidth, - config.viewInfo.stopRenderingLineAfter, - config.viewInfo.renderWhitespace, - config.viewInfo.renderControlCharacters, - config.viewInfo.fontLigatures, + fontInfo.spaceWidth, + options.get(EditorOption.stopRenderingLineAfter), + options.get(EditorOption.renderWhitespace), + options.get(EditorOption.renderControlCharacters), + options.get(EditorOption.fontLigatures), null // Send no selections, original line cannot be selected ), sb); diff --git a/src/vs/editor/browser/widget/diffReview.ts b/src/vs/editor/browser/widget/diffReview.ts index 33c88f82cf..b175fd1daf 100644 --- a/src/vs/editor/browser/widget/diffReview.ts +++ b/src/vs/editor/browser/widget/diffReview.ts @@ -17,7 +17,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { IComputedEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; import { Position } from 'vs/editor/common/core/position'; import { ILineChange, ScrollType } from 'vs/editor/common/editorCommon'; @@ -524,8 +524,8 @@ export class DiffReview extends Disposable { private _render(): void { - const originalOpts = this._diffEditor.getOriginalEditor().getConfiguration(); - const modifiedOpts = this._diffEditor.getModifiedEditor().getConfiguration(); + const originalOptions = this._diffEditor.getOriginalEditor().getOptions(); + const modifiedOptions = this._diffEditor.getModifiedEditor().getOptions(); const originalModel = this._diffEditor.getOriginalEditor().getModel(); const modifiedModel = this._diffEditor.getModifiedEditor().getModel(); @@ -551,7 +551,7 @@ export class DiffReview extends Disposable { let container = document.createElement('div'); container.className = 'diff-review-table'; container.setAttribute('role', 'list'); - Configuration.applyFontInfoSlow(container, modifiedOpts.fontInfo); + Configuration.applyFontInfoSlow(container, modifiedOptions.get(EditorOption.fontInfo)); let minOriginalLine = 0; let maxOriginalLine = 0; @@ -620,7 +620,7 @@ export class DiffReview extends Disposable { let modLine = minModifiedLine; for (let i = 0, len = diffs.length; i < len; i++) { const diffEntry = diffs[i]; - DiffReview._renderSection(container, diffEntry, modLine, this._width, originalOpts, originalModel, originalModelOpts, modifiedOpts, modifiedModel, modifiedModelOpts); + DiffReview._renderSection(container, diffEntry, modLine, this._width, originalOptions, originalModel, originalModelOpts, modifiedOptions, modifiedModel, modifiedModelOpts); if (diffEntry.modifiedLineStart !== 0) { modLine = diffEntry.modifiedLineEnd; } @@ -633,8 +633,8 @@ export class DiffReview extends Disposable { private static _renderSection( dest: HTMLElement, diffEntry: DiffEntry, modLine: number, width: number, - originalOpts: editorOptions.InternalEditorOptions, originalModel: ITextModel, originalModelOpts: TextModelResolvedOptions, - modifiedOpts: editorOptions.InternalEditorOptions, modifiedModel: ITextModel, modifiedModelOpts: TextModelResolvedOptions + originalOptions: IComputedEditorOptions, originalModel: ITextModel, originalModelOpts: TextModelResolvedOptions, + modifiedOptions: IComputedEditorOptions, modifiedModel: ITextModel, modifiedModelOpts: TextModelResolvedOptions ): void { const type = diffEntry.getType(); @@ -665,8 +665,11 @@ export class DiffReview extends Disposable { originalLineEnd - originalLineStart ); - const originalLineNumbersWidth = originalOpts.layoutInfo.glyphMarginWidth + originalOpts.layoutInfo.lineNumbersWidth; - const modifiedLineNumbersWidth = 10 + modifiedOpts.layoutInfo.glyphMarginWidth + modifiedOpts.layoutInfo.lineNumbersWidth; + const originalLayoutInfo = originalOptions.get(EditorOption.layoutInfo); + const originalLineNumbersWidth = originalLayoutInfo.glyphMarginWidth + originalLayoutInfo.lineNumbersWidth; + + const modifiedLayoutInfo = modifiedOptions.get(EditorOption.layoutInfo); + const modifiedLineNumbersWidth = 10 + modifiedLayoutInfo.glyphMarginWidth + modifiedLayoutInfo.lineNumbersWidth; for (let i = 0; i <= cnt; i++) { const originalLine = (originalLineStart === 0 ? 0 : originalLineStart + i); @@ -716,12 +719,12 @@ export class DiffReview extends Disposable { let lineContent: string; if (modifiedLine !== 0) { cell.insertAdjacentHTML('beforeend', - this._renderLine(modifiedModel, modifiedOpts, modifiedModelOpts.tabSize, modifiedLine) + this._renderLine(modifiedModel, modifiedOptions, modifiedModelOpts.tabSize, modifiedLine) ); lineContent = modifiedModel.getLineContent(modifiedLine); } else { cell.insertAdjacentHTML('beforeend', - this._renderLine(originalModel, originalOpts, originalModelOpts.tabSize, originalLine) + this._renderLine(originalModel, originalOptions, originalModelOpts.tabSize, originalLine) ); lineContent = originalModel.getLineContent(originalLine); } @@ -748,8 +751,9 @@ export class DiffReview extends Disposable { } } - private static _renderLine(model: ITextModel, config: editorOptions.InternalEditorOptions, tabSize: number, lineNumber: number): string { + private static _renderLine(model: ITextModel, options: IComputedEditorOptions, tabSize: number, lineNumber: number): string { const lineContent = model.getLineContent(lineNumber); + const fontInfo = options.get(EditorOption.fontInfo); const defaultMetadata = ( (FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET) @@ -766,8 +770,8 @@ export class DiffReview extends Disposable { const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, model.mightContainNonBasicASCII()); const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, model.mightContainRTL()); const r = renderViewLine(new RenderLineInput( - (config.fontInfo.isMonospace && !config.viewInfo.disableMonospaceOptimizations), - config.fontInfo.canUseHalfwidthRightwardsArrow, + (fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations) && !options.get(EditorOption.fontLigatures)), + fontInfo.canUseHalfwidthRightwardsArrow, lineContent, false, isBasicASCII, @@ -776,11 +780,11 @@ export class DiffReview extends Disposable { lineTokens, [], tabSize, - config.fontInfo.spaceWidth, - config.viewInfo.stopRenderingLineAfter, - config.viewInfo.renderWhitespace, - config.viewInfo.renderControlCharacters, - config.viewInfo.fontLigatures, + fontInfo.spaceWidth, + options.get(EditorOption.stopRenderingLineAfter), + options.get(EditorOption.renderWhitespace), + options.get(EditorOption.renderControlCharacters), + options.get(EditorOption.fontLigatures), null )); diff --git a/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts b/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts index f7ffd038bb..9affe4c81c 100644 --- a/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts +++ b/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts @@ -8,7 +8,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; -import { IConfigurationChangedEvent, IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -36,7 +36,7 @@ export class EmbeddedCodeEditorWidget extends CodeEditorWidget { @INotificationService notificationService: INotificationService, @IAccessibilityService accessibilityService: IAccessibilityService ) { - super(domElement, parentEditor.getRawConfiguration(), {}, instantiationService, codeEditorService, commandService, contextKeyService, themeService, notificationService, accessibilityService); + super(domElement, parentEditor.getRawOptions(), {}, instantiationService, codeEditorService, commandService, contextKeyService, themeService, notificationService, accessibilityService); this._parentEditor = parentEditor; this._overwriteOptions = options; @@ -44,15 +44,15 @@ export class EmbeddedCodeEditorWidget extends CodeEditorWidget { // Overwrite parent's options super.updateOptions(this._overwriteOptions); - this._register(parentEditor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => this._onParentConfigurationChanged(e))); + this._register(parentEditor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => this._onParentConfigurationChanged(e))); } getParentEditor(): ICodeEditor { return this._parentEditor; } - private _onParentConfigurationChanged(e: IConfigurationChangedEvent): void { - super.updateOptions(this._parentEditor.getRawConfiguration()); + private _onParentConfigurationChanged(e: ConfigurationChangedEvent): void { + super.updateOptions(this._parentEditor.getRawOptions()); super.updateOptions(this._overwriteOptions); } @@ -80,7 +80,7 @@ export class EmbeddedDiffEditorWidget extends DiffEditorWidget { @IContextMenuService contextMenuService: IContextMenuService, @IClipboardService clipboardService: IClipboardService ) { - super(domElement, parentEditor.getRawConfiguration(), editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService, clipboardService); + super(domElement, parentEditor.getRawOptions(), clipboardService, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService); this._parentEditor = parentEditor; this._overwriteOptions = options; @@ -95,8 +95,8 @@ export class EmbeddedDiffEditorWidget extends DiffEditorWidget { return this._parentEditor; } - private _onParentConfigurationChanged(e: IConfigurationChangedEvent): void { - super.updateOptions(this._parentEditor.getRawConfiguration()); + private _onParentConfigurationChanged(e: ConfigurationChangedEvent): void { + super.updateOptions(this._parentEditor.getRawOptions()); super.updateOptions(this._overwriteOptions); } diff --git a/src/vs/editor/browser/widget/inlineDiffMargin.ts b/src/vs/editor/browser/widget/inlineDiffMargin.ts index 2d1748d0d0..f7c1378b44 100644 --- a/src/vs/editor/browser/widget/inlineDiffMargin.ts +++ b/src/vs/editor/browser/widget/inlineDiffMargin.ts @@ -12,6 +12,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService import * as editorBrowser from 'vs/editor/browser/editorBrowser'; import { Range } from 'vs/editor/common/core/range'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface IDiffLinesChange { readonly originalStartLineNumber: number; @@ -58,7 +59,7 @@ export class InlineDiffMargin extends Disposable { this._diffActions = document.createElement('div'); this._diffActions.className = 'lightbulb-glyph'; this._diffActions.style.position = 'absolute'; - const lineHeight = editor.getConfiguration().lineHeight; + const lineHeight = editor.getOption(EditorOption.lineHeight); const lineFeed = editor.getModel()!.getEOL(); this._diffActions.style.right = '0px'; this._diffActions.style.visibility = 'hidden'; @@ -66,26 +67,27 @@ export class InlineDiffMargin extends Disposable { this._diffActions.style.lineHeight = `${lineHeight}px`; this._marginDomNode.appendChild(this._diffActions); - const actions = [ - new Action( - 'diff.clipboard.copyDeletedContent', - nls.localize('diff.clipboard.copyDeletedContent.label', "Copy deleted lines content to clipboard"), - undefined, - true, - async () => { - await this._clipboardService.writeText(diff.originalContent.join(lineFeed) + lineFeed); - } - ) - ]; + const actions: Action[] = []; + + // default action + actions.push(new Action( + 'diff.clipboard.copyDeletedContent', + diff.originalEndLineNumber > diff.modifiedStartLineNumber + ? nls.localize('diff.clipboard.copyDeletedLinesContent.label', "Copy deleted lines") + : nls.localize('diff.clipboard.copyDeletedLinesContent.single.label', "Copy deleted line"), + undefined, + true, + async () => { + await this._clipboardService.writeText(diff.originalContent.join(lineFeed) + lineFeed); + } + )); let currentLineNumberOffset = 0; - let copyLineAction: Action | undefined = undefined; - if (diff.originalEndLineNumber > diff.modifiedStartLineNumber) { copyLineAction = new Action( 'diff.clipboard.copyDeletedLineContent', - nls.localize('diff.clipboard.copyDeletedLineContent.label', "Copy deleted line {0} content to clipboard", diff.originalStartLineNumber), + nls.localize('diff.clipboard.copyDeletedLineContent.label', "Copy deleted line ({0})", diff.originalStartLineNumber), undefined, true, async () => { @@ -96,7 +98,7 @@ export class InlineDiffMargin extends Disposable { actions.push(copyLineAction); } - const readOnly = editor.getConfiguration().readOnly; + const readOnly = editor.getOption(EditorOption.readOnly); if (!readOnly) { actions.push(new Action('diff.inline.revertChange', nls.localize('diff.inline.revertChange.label', "Revert this change"), undefined, true, async () => { if (diff.modifiedEndLineNumber === 0) { @@ -121,24 +123,31 @@ export class InlineDiffMargin extends Disposable { })); } - this._register(dom.addStandardDisposableListener(this._diffActions, 'mousedown', e => { - const { top, height } = dom.getDomNodePagePosition(this._diffActions); - let pad = Math.floor(lineHeight / 3) + lineHeight; + const showContextMenu = (x: number, y: number) => { this._contextMenuService.showContextMenu({ getAnchor: () => { return { - x: e.posx, - y: top + height + pad + x, + y }; }, getActions: () => { if (copyLineAction) { - copyLineAction.label = nls.localize('diff.clipboard.copyDeletedLineContent.label', "Copy deleted line {0} content to clipboard", diff.originalStartLineNumber + currentLineNumberOffset); + copyLineAction.label = nls.localize('diff.clipboard.copyDeletedLineContent.label', "Copy deleted line ({0})", diff.originalStartLineNumber + currentLineNumberOffset); } return actions; }, autoSelectFirstItem: true }); + }; + + this._register(dom.addStandardDisposableListener(this._diffActions, 'mousedown', e => { + const { top, height } = dom.getDomNodePagePosition(this._diffActions); + let pad = Math.floor(lineHeight / 3); + e.preventDefault(); + + showContextMenu(e.posx, top + height + pad); + })); this._register(editor.onMouseMove((e: editorBrowser.IEditorMouseEvent) => { @@ -155,6 +164,22 @@ export class InlineDiffMargin extends Disposable { this.visibility = false; } })); + + this._register(editor.onMouseDown((e: editorBrowser.IEditorMouseEvent) => { + if (!e.event.rightButton) { + return; + } + + if (e.target.type === editorBrowser.MouseTargetType.CONTENT_VIEW_ZONE || e.target.type === editorBrowser.MouseTargetType.GUTTER_VIEW_ZONE) { + const viewZoneId = e.target.detail.viewZoneId; + + if (viewZoneId === this._viewZoneId) { + e.event.preventDefault(); + currentLineNumberOffset = this._updateLightBulbPosition(this._marginDomNode, e.event.browserEvent.y, lineHeight); + showContextMenu(e.event.posx, e.event.posy + lineHeight); + } + } + })); } private _updateLightBulbPosition(marginDomNode: HTMLElement, y: number, lineHeight: number): number { diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index f14d4a28c2..1336ba6f84 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -7,16 +7,13 @@ import * as nls from 'vs/nls'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; -import * as platform from 'vs/base/common/platform'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import * as arrays from 'vs/base/common/arrays'; +import { IEditorOptions, editorOptionsRegistry, ValidatedEditorOptions, IEnvironmentalOptions, IComputedEditorOptions, ConfigurationChangedEvent, EDITOR_MODEL_DEFAULTS, EditorOption, FindComputedEditorOptionValueById } from 'vs/editor/common/config/editorOptions'; import { EditorZoom } from 'vs/editor/common/config/editorZoom'; import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationRegistry, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; -import EDITOR_DEFAULTS = editorOptions.EDITOR_DEFAULTS; -import EDITOR_FONT_DEFAULTS = editorOptions.EDITOR_FONT_DEFAULTS; -import EDITOR_MODEL_DEFAULTS = editorOptions.EDITOR_MODEL_DEFAULTS; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; /** @@ -63,35 +60,187 @@ export interface IEnvConfiguration { const hasOwnProperty = Object.hasOwnProperty; +export class ComputedEditorOptions implements IComputedEditorOptions { + private readonly _values: any[] = []; + public _read(id: EditorOption): T { + return this._values[id]; + } + public get(id: T): FindComputedEditorOptionValueById { + return this._values[id]; + } + public _write(id: EditorOption, value: T): void { + this._values[id] = value; + } +} + +class RawEditorOptions { + private readonly _values: any[] = []; + public _read(id: EditorOption): T | undefined { + return this._values[id]; + } + public _write(id: EditorOption, value: T | undefined): void { + this._values[id] = value; + } +} + +class EditorConfiguration2 { + public static readOptions(_options: IEditorOptions): RawEditorOptions { + const options: { [key: string]: any; } = _options; + const result = new RawEditorOptions(); + for (const editorOption of editorOptionsRegistry) { + const value = (editorOption.name === '_never_' ? undefined : options[editorOption.name]); + result._write(editorOption.id, value); + } + return result; + } + + public static validateOptions(options: RawEditorOptions): ValidatedEditorOptions { + const result = new ValidatedEditorOptions(); + for (const editorOption of editorOptionsRegistry) { + result._write(editorOption.id, editorOption.validate(options._read(editorOption.id))); + } + return result; + } + + public static computeOptions(options: ValidatedEditorOptions, env: IEnvironmentalOptions): ComputedEditorOptions { + const result = new ComputedEditorOptions(); + for (const editorOption of editorOptionsRegistry) { + result._write(editorOption.id, editorOption.compute(env, result, options._read(editorOption.id))); + } + return result; + } + + private static _deepEquals(a: T, b: T): boolean { + if (typeof a !== 'object' || typeof b !== 'object') { + return (a === b); + } + if (Array.isArray(a) || Array.isArray(b)) { + return (Array.isArray(a) && Array.isArray(b) ? arrays.equals(a, b) : false); + } + for (let key in a) { + if (!EditorConfiguration2._deepEquals(a[key], b[key])) { + return false; + } + } + return true; + } + + public static checkEquals(a: ComputedEditorOptions, b: ComputedEditorOptions): ConfigurationChangedEvent | null { + const result: boolean[] = []; + let somethingChanged = false; + for (const editorOption of editorOptionsRegistry) { + const changed = !EditorConfiguration2._deepEquals(a._read(editorOption.id), b._read(editorOption.id)); + result[editorOption.id] = changed; + if (changed) { + somethingChanged = true; + } + } + return (somethingChanged ? new ConfigurationChangedEvent(result) : null); + } +} + +/** + * Compatibility with old options + */ +function migrateOptions(options: IEditorOptions): void { + const wordWrap = options.wordWrap; + if (wordWrap === true) { + options.wordWrap = 'on'; + } else if (wordWrap === false) { + options.wordWrap = 'off'; + } + + const lineNumbers = options.lineNumbers; + if (lineNumbers === true) { + options.lineNumbers = 'on'; + } else if (lineNumbers === false) { + options.lineNumbers = 'off'; + } + + const autoClosingBrackets = options.autoClosingBrackets; + if (autoClosingBrackets === false) { + options.autoClosingBrackets = 'never'; + options.autoClosingQuotes = 'never'; + options.autoSurround = 'never'; + } + + const cursorBlinking = options.cursorBlinking; + if (cursorBlinking === 'visible') { + options.cursorBlinking = 'solid'; + } + + const renderWhitespace = options.renderWhitespace; + if (renderWhitespace === true) { + options.renderWhitespace = 'boundary'; + } else if (renderWhitespace === false) { + options.renderWhitespace = 'none'; + } + + const renderLineHighlight = options.renderLineHighlight; + if (renderLineHighlight === true) { + options.renderLineHighlight = 'line'; + } else if (renderLineHighlight === false) { + options.renderLineHighlight = 'none'; + } + + const acceptSuggestionOnEnter = options.acceptSuggestionOnEnter; + if (acceptSuggestionOnEnter === true) { + options.acceptSuggestionOnEnter = 'on'; + } else if (acceptSuggestionOnEnter === false) { + options.acceptSuggestionOnEnter = 'off'; + } + + const tabCompletion = options.tabCompletion; + if (tabCompletion === false) { + options.tabCompletion = 'off'; + } else if (tabCompletion === true) { + options.tabCompletion = 'onlySnippets'; + } + + const hover = options.hover; + if (hover === true) { + options.hover = { + enabled: true + }; + } else if (hover === false) { + options.hover = { + enabled: false + }; + } +} + +function deepCloneAndMigrateOptions(_options: IEditorOptions): IEditorOptions { + const options = objects.deepClone(_options); + migrateOptions(options); + return options; +} + export abstract class CommonEditorConfiguration extends Disposable implements editorCommon.IConfiguration { + private _onDidChange = this._register(new Emitter()); + public readonly onDidChange: Event = this._onDidChange.event; + public readonly isSimpleWidget: boolean; - protected _rawOptions: editorOptions.IEditorOptions; - protected _validatedOptions: editorOptions.IValidatedEditorOptions; - public editor!: editorOptions.InternalEditorOptions; + public options!: ComputedEditorOptions; + private _isDominatedByLongLines: boolean; private _lineNumbersDigitCount: number; - private _onDidChange = this._register(new Emitter()); - public readonly onDidChange: Event = this._onDidChange.event; + private _rawOptions: IEditorOptions; + private _readOptions: RawEditorOptions; + protected _validatedOptions: ValidatedEditorOptions; - constructor(isSimpleWidget: boolean, options: editorOptions.IEditorOptions) { + constructor(isSimpleWidget: boolean, _options: IEditorOptions) { super(); - this.isSimpleWidget = isSimpleWidget; - // Do a "deep clone of sorts" on the incoming options - this._rawOptions = objects.mixin({}, options || {}); - this._rawOptions.scrollbar = objects.mixin({}, this._rawOptions.scrollbar || {}); - this._rawOptions.minimap = objects.mixin({}, this._rawOptions.minimap || {}); - this._rawOptions.find = objects.mixin({}, this._rawOptions.find || {}); - this._rawOptions.hover = objects.mixin({}, this._rawOptions.hover || {}); - this._rawOptions.parameterHints = objects.mixin({}, this._rawOptions.parameterHints || {}); - - this._validatedOptions = editorOptions.EditorOptionsValidator.validate(this._rawOptions, EDITOR_DEFAULTS); this._isDominatedByLongLines = false; this._lineNumbersDigitCount = 1; + this._rawOptions = deepCloneAndMigrateOptions(_options); + this._readOptions = EditorConfiguration2.readOptions(this._rawOptions); + this._validatedOptions = EditorConfiguration2.validateOptions(this._readOptions); + this._register(EditorZoom.onDidChangeZoomLevel(_ => this._recomputeOptions())); this._register(TabFocus.onDidChangeTabFocus(_ => this._recomputeOptions())); } @@ -104,29 +253,32 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed } protected _recomputeOptions(): void { - const oldOptions = this.editor; + const oldOptions = this.options; const newOptions = this._computeInternalOptions(); - if (oldOptions && oldOptions.equals(newOptions)) { - return; - } + if (!oldOptions) { + this.options = newOptions; + } else { + const changeEvent = EditorConfiguration2.checkEquals(oldOptions, newOptions); - this.editor = newOptions; + if (changeEvent === null) { + // nothing changed! + return; + } - if (oldOptions) { - this._onDidChange.fire(oldOptions.createChangeEvent(newOptions)); + this.options = newOptions; + this._onDidChange.fire(changeEvent); } } - public getRawOptions(): editorOptions.IEditorOptions { + public getRawOptions(): IEditorOptions { return this._rawOptions; } - private _computeInternalOptions(): editorOptions.InternalEditorOptions { - const opts = this._validatedOptions; + private _computeInternalOptions(): ComputedEditorOptions { const partialEnv = this._getEnvConfiguration(); - const bareFontInfo = BareFontInfo.createFromRawSettings(this._rawOptions, partialEnv.zoomLevel, this.isSimpleWidget); - const env: editorOptions.IEnvironmentalOptions = { + const bareFontInfo = BareFontInfo.createFromValidatedSettings(this._validatedOptions, partialEnv.zoomLevel, this.isSimpleWidget); + const env: IEnvironmentalOptions = { outerWidth: partialEnv.outerWidth, outerHeight: partialEnv.outerHeight, fontInfo: this.readConfiguration(bareFontInfo), @@ -138,7 +290,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed tabFocusMode: TabFocus.getTabFocusMode(), accessibilitySupport: partialEnv.accessibilitySupport }; - return editorOptions.InternalEditorOptionsFactory.createInternalEditorOptions(env, opts); + return EditorConfiguration2.computeOptions(this._validatedOptions, env); } private static _primitiveArrayEquals(a: any[], b: any[]): boolean { @@ -181,15 +333,18 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed return true; } - public updateOptions(newOptions: editorOptions.IEditorOptions): void { - if (typeof newOptions === 'undefined') { + public updateOptions(_newOptions: IEditorOptions): void { + if (typeof _newOptions === 'undefined') { return; } + const newOptions = deepCloneAndMigrateOptions(_newOptions); if (CommonEditorConfiguration._subsetEquals(this._rawOptions, newOptions)) { return; } this._rawOptions = objects.mixin(this._rawOptions, newOptions || {}); - this._validatedOptions = editorOptions.EditorOptionsValidator.validate(this._rawOptions, EDITOR_DEFAULTS); + this._readOptions = EditorConfiguration2.readOptions(this._rawOptions); + this._validatedOptions = EditorConfiguration2.validateOptions(this._readOptions); + this._recomputeOptions(); } @@ -223,877 +378,130 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed const configurationRegistry = Registry.as(Extensions.Configuration); const editorConfiguration: IConfigurationNode = { - 'id': 'editor', - 'order': 5, - 'type': 'object', - 'title': nls.localize('editorConfigurationTitle', "Editor"), - 'overridable': true, - 'scope': ConfigurationScope.RESOURCE, - 'properties': { - 'editor.fontFamily': { - 'type': 'string', - 'default': EDITOR_FONT_DEFAULTS.fontFamily, - 'description': nls.localize('fontFamily', "Controls the font family.") - }, - 'editor.fontWeight': { - 'type': 'string', - 'enum': ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'], - 'default': EDITOR_FONT_DEFAULTS.fontWeight, - 'description': nls.localize('fontWeight', "Controls the font weight.") - }, - 'editor.fontSize': { - 'type': 'number', - 'default': EDITOR_FONT_DEFAULTS.fontSize, - 'description': nls.localize('fontSize', "Controls the font size in pixels.") - }, - 'editor.lineHeight': { - 'type': 'number', - 'default': EDITOR_FONT_DEFAULTS.lineHeight, - 'description': nls.localize('lineHeight', "Controls the line height. Use 0 to compute the line height from the font size.") - }, - 'editor.letterSpacing': { - 'type': 'number', - 'default': EDITOR_FONT_DEFAULTS.letterSpacing, - 'description': nls.localize('letterSpacing', "Controls the letter spacing in pixels.") - }, - 'editor.lineNumbers': { - 'type': 'string', - 'enum': ['off', 'on', 'relative', 'interval'], - 'enumDescriptions': [ - nls.localize('lineNumbers.off', "Line numbers are not rendered."), - nls.localize('lineNumbers.on', "Line numbers are rendered as absolute number."), - nls.localize('lineNumbers.relative', "Line numbers are rendered as distance in lines to cursor position."), - nls.localize('lineNumbers.interval', "Line numbers are rendered every 10 lines.") - ], - 'default': 'on', - 'description': nls.localize('lineNumbers', "Controls the display of line numbers.") - }, - 'editor.cursorSurroundingLines': { - 'type': 'number', - 'default': EDITOR_DEFAULTS.viewInfo.cursorSurroundingLines, - 'description': nls.localize('cursorSurroundingLines', "Controls the minimal number of visible leading and trailing lines surrounding the cursor. Known as 'scrollOff' or `scrollOffset` in some other editors.") - }, - 'editor.renderFinalNewline': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.renderFinalNewline, - 'description': nls.localize('renderFinalNewline', "Render last line number when the file ends with a newline.") - }, - 'editor.rulers': { - 'type': 'array', - 'items': { - 'type': 'number' - }, - 'default': EDITOR_DEFAULTS.viewInfo.rulers, - 'description': nls.localize('rulers', "Render vertical rulers after a certain number of monospace characters. Use multiple values for multiple rulers. No rulers are drawn if array is empty.") - }, - 'editor.wordSeparators': { - 'type': 'string', - 'default': EDITOR_DEFAULTS.wordSeparators, - 'description': nls.localize('wordSeparators', "Characters that will be used as word separators when doing word related navigations or operations.") - }, + id: 'editor', + order: 5, + type: 'object', + title: nls.localize('editorConfigurationTitle', "Editor"), + overridable: true, + scope: ConfigurationScope.RESOURCE, + properties: { 'editor.tabSize': { - 'type': 'number', - 'default': EDITOR_MODEL_DEFAULTS.tabSize, - 'minimum': 1, - 'markdownDescription': nls.localize('tabSize', "The number of spaces a tab is equal to. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") + type: 'number', + default: EDITOR_MODEL_DEFAULTS.tabSize, + minimum: 1, + markdownDescription: nls.localize('tabSize', "The number of spaces a tab is equal to. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") }, // 'editor.indentSize': { // 'anyOf': [ // { - // 'type': 'string', - // 'enum': ['tabSize'] + // type: 'string', + // enum: ['tabSize'] // }, // { - // 'type': 'number', - // 'minimum': 1 + // type: 'number', + // minimum: 1 // } // ], - // 'default': 'tabSize', - // 'markdownDescription': nls.localize('indentSize', "The number of spaces used for indentation or 'tabSize' to use the value from `#editor.tabSize#`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") + // default: 'tabSize', + // markdownDescription: nls.localize('indentSize', "The number of spaces used for indentation or 'tabSize' to use the value from `#editor.tabSize#`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") // }, 'editor.insertSpaces': { - 'type': 'boolean', - 'default': EDITOR_MODEL_DEFAULTS.insertSpaces, - 'markdownDescription': nls.localize('insertSpaces', "Insert spaces when pressing `Tab`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") + type: 'boolean', + default: EDITOR_MODEL_DEFAULTS.insertSpaces, + markdownDescription: nls.localize('insertSpaces', "Insert spaces when pressing `Tab`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") }, 'editor.detectIndentation': { - 'type': 'boolean', - 'default': EDITOR_MODEL_DEFAULTS.detectIndentation, - 'markdownDescription': nls.localize('detectIndentation', "Controls whether `#editor.tabSize#` and `#editor.insertSpaces#` will be automatically detected when a file is opened based on the file contents.") - }, - 'editor.roundedSelection': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.roundedSelection, - 'description': nls.localize('roundedSelection', "Controls whether selections should have rounded corners.") - }, - 'editor.scrollBeyondLastLine': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.scrollBeyondLastLine, - 'description': nls.localize('scrollBeyondLastLine', "Controls whether the editor will scroll beyond the last line.") - }, - 'editor.scrollBeyondLastColumn': { - 'type': 'number', - 'default': EDITOR_DEFAULTS.viewInfo.scrollBeyondLastColumn, - 'description': nls.localize('scrollBeyondLastColumn', "Controls the number of extra characters beyond which the editor will scroll horizontally.") - }, - 'editor.smoothScrolling': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.smoothScrolling, - 'description': nls.localize('smoothScrolling', "Controls whether the editor will scroll using an animation.") - }, - 'editor.minimap.enabled': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.minimap.enabled, - 'description': nls.localize('minimap.enabled', "Controls whether the minimap is shown.") - }, - 'editor.minimap.side': { - 'type': 'string', - 'enum': ['left', 'right'], - 'default': EDITOR_DEFAULTS.viewInfo.minimap.side, - 'description': nls.localize('minimap.side', "Controls the side where to render the minimap.") - }, - 'editor.minimap.showSlider': { - 'type': 'string', - 'enum': ['always', 'mouseover'], - 'default': EDITOR_DEFAULTS.viewInfo.minimap.showSlider, - 'description': nls.localize('minimap.showSlider', "Controls whether the minimap slider is automatically hidden.") - }, - 'editor.minimap.renderCharacters': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.minimap.renderCharacters, - 'description': nls.localize('minimap.renderCharacters', "Render the actual characters on a line as opposed to color blocks.") - }, - 'editor.minimap.maxColumn': { - 'type': 'number', - 'default': EDITOR_DEFAULTS.viewInfo.minimap.maxColumn, - 'description': nls.localize('minimap.maxColumn', "Limit the width of the minimap to render at most a certain number of columns.") - }, - 'editor.hover.enabled': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.hover.enabled, - 'description': nls.localize('hover.enabled', "Controls whether the hover is shown.") - }, - 'editor.hover.delay': { - 'type': 'number', - 'default': EDITOR_DEFAULTS.contribInfo.hover.delay, - 'description': nls.localize('hover.delay', "Controls the delay in milliseconds after which the hover is shown.") - }, - 'editor.hover.sticky': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.hover.sticky, - 'description': nls.localize('hover.sticky', "Controls whether the hover should remain visible when mouse is moved over it.") - }, - 'editor.find.seedSearchStringFromSelection': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.find.seedSearchStringFromSelection, - 'description': nls.localize('find.seedSearchStringFromSelection', "Controls whether the search string in the Find Widget is seeded from the editor selection.") - }, - 'editor.find.autoFindInSelection': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.find.autoFindInSelection, - 'description': nls.localize('find.autoFindInSelection', "Controls whether the find operation is carried out on selected text or the entire file in the editor.") - }, - 'editor.find.globalFindClipboard': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.find.globalFindClipboard, - 'description': nls.localize('find.globalFindClipboard', "Controls whether the Find Widget should read or modify the shared find clipboard on macOS."), - 'included': platform.isMacintosh - }, - 'editor.find.addExtraSpaceOnTop': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('find.addExtraSpaceOnTop', "Controls whether the Find Widget should add extra lines on top of the editor. When true, you can scroll beyond the first line when the Find Widget is visible.") - }, - 'editor.wordWrap': { - 'type': 'string', - 'enum': ['off', 'on', 'wordWrapColumn', 'bounded'], - 'markdownEnumDescriptions': [ - nls.localize('wordWrap.off', "Lines will never wrap."), - nls.localize('wordWrap.on', "Lines will wrap at the viewport width."), - nls.localize({ - key: 'wordWrap.wordWrapColumn', - comment: [ - '- `editor.wordWrapColumn` refers to a different setting and should not be localized.' - ] - }, "Lines will wrap at `#editor.wordWrapColumn#`."), - nls.localize({ - key: 'wordWrap.bounded', - comment: [ - '- viewport means the edge of the visible window size.', - '- `editor.wordWrapColumn` refers to a different setting and should not be localized.' - ] - }, "Lines will wrap at the minimum of viewport and `#editor.wordWrapColumn#`."), - ], - 'default': EDITOR_DEFAULTS.wordWrap, - 'description': nls.localize({ - key: 'wordWrap', - comment: [ - '- \'off\', \'on\', \'wordWrapColumn\' and \'bounded\' refer to values the setting can take and should not be localized.', - '- `editor.wordWrapColumn` refers to a different setting and should not be localized.' - ] - }, "Controls how lines should wrap.") - }, - 'editor.wordWrapColumn': { - 'type': 'integer', - 'default': EDITOR_DEFAULTS.wordWrapColumn, - 'minimum': 1, - 'markdownDescription': nls.localize({ - key: 'wordWrapColumn', - comment: [ - '- `editor.wordWrap` refers to a different setting and should not be localized.', - '- \'wordWrapColumn\' and \'bounded\' refer to values the different setting can take and should not be localized.' - ] - }, "Controls the wrapping column of the editor when `#editor.wordWrap#` is `wordWrapColumn` or `bounded`.") - }, - 'editor.wrappingIndent': { - 'type': 'string', - 'enum': ['none', 'same', 'indent', 'deepIndent'], - enumDescriptions: [ - nls.localize('wrappingIndent.none', "No indentation. Wrapped lines begin at column 1."), - nls.localize('wrappingIndent.same', "Wrapped lines get the same indentation as the parent."), - nls.localize('wrappingIndent.indent', "Wrapped lines get +1 indentation toward the parent."), - nls.localize('wrappingIndent.deepIndent', "Wrapped lines get +2 indentation toward the parent."), - ], - 'default': 'same', - 'description': nls.localize('wrappingIndent', "Controls the indentation of wrapped lines."), - }, - 'editor.mouseWheelScrollSensitivity': { - 'type': 'number', - 'default': EDITOR_DEFAULTS.viewInfo.scrollbar.mouseWheelScrollSensitivity, - 'markdownDescription': nls.localize('mouseWheelScrollSensitivity', "A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.") - }, - 'editor.fastScrollSensitivity': { - 'type': 'number', - 'default': EDITOR_DEFAULTS.viewInfo.scrollbar.fastScrollSensitivity, - 'markdownDescription': nls.localize('fastScrollSensitivity', "Scrolling speed multiplier when pressing `Alt`.") - }, - 'editor.multiCursorModifier': { - 'type': 'string', - 'enum': ['ctrlCmd', 'alt'], - 'markdownEnumDescriptions': [ - nls.localize('multiCursorModifier.ctrlCmd', "Maps to `Control` on Windows and Linux and to `Command` on macOS."), - nls.localize('multiCursorModifier.alt', "Maps to `Alt` on Windows and Linux and to `Option` on macOS.") - ], - 'default': 'alt', - 'markdownDescription': nls.localize({ - key: 'multiCursorModifier', - comment: [ - '- `ctrlCmd` refers to a value the setting can take and should not be localized.', - '- `Control` and `Command` refer to the modifier keys Ctrl or Cmd on the keyboard and can be localized.' - ] - }, "The modifier to be used to add multiple cursors with the mouse. The Go To Definition and Open Link mouse gestures will adapt such that they do not conflict with the multicursor modifier. [Read more](https://code.visualstudio.com/docs/editor/codebasics#_multicursor-modifier).") - }, - 'editor.multiCursorMergeOverlapping': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.multiCursorMergeOverlapping, - 'description': nls.localize('multiCursorMergeOverlapping', "Merge multiple cursors when they are overlapping.") - }, - 'editor.quickSuggestions': { - 'anyOf': [ - { - type: 'boolean', - }, - { - type: 'object', - properties: { - strings: { - type: 'boolean', - default: false, - description: nls.localize('quickSuggestions.strings', "Enable quick suggestions inside strings.") - }, - comments: { - type: 'boolean', - default: false, - description: nls.localize('quickSuggestions.comments', "Enable quick suggestions inside comments.") - }, - other: { - type: 'boolean', - default: true, - description: nls.localize('quickSuggestions.other', "Enable quick suggestions outside of strings and comments.") - }, - } - } - ], - 'default': EDITOR_DEFAULTS.contribInfo.quickSuggestions, - 'description': nls.localize('quickSuggestions', "Controls whether suggestions should automatically show up while typing.") - }, - 'editor.quickSuggestionsDelay': { - 'type': 'integer', - 'default': EDITOR_DEFAULTS.contribInfo.quickSuggestionsDelay, - 'minimum': 0, - 'description': nls.localize('quickSuggestionsDelay', "Controls the delay in milliseconds after which quick suggestions will show up.") - }, - 'editor.parameterHints.enabled': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.parameterHints.enabled, - 'description': nls.localize('parameterHints.enabled', "Enables a pop-up that shows parameter documentation and type information as you type.") - }, - 'editor.parameterHints.cycle': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.parameterHints.cycle, - 'description': nls.localize('parameterHints.cycle', "Controls whether the parameter hints menu cycles or closes when reaching the end of the list.") - }, - 'editor.autoClosingBrackets': { - type: 'string', - enum: ['always', 'languageDefined', 'beforeWhitespace', 'never'], - enumDescriptions: [ - '', - nls.localize('editor.autoClosingBrackets.languageDefined', "Use language configurations to determine when to autoclose brackets."), - nls.localize('editor.autoClosingBrackets.beforeWhitespace', "Autoclose brackets only when the cursor is to the left of whitespace."), - '', - - ], - 'default': EDITOR_DEFAULTS.autoClosingBrackets, - 'description': nls.localize('autoClosingBrackets', "Controls whether the editor should automatically close brackets after the user adds an opening bracket.") - }, - 'editor.autoClosingQuotes': { - type: 'string', - enum: ['always', 'languageDefined', 'beforeWhitespace', 'never'], - enumDescriptions: [ - '', - nls.localize('editor.autoClosingQuotes.languageDefined', "Use language configurations to determine when to autoclose quotes."), - nls.localize('editor.autoClosingQuotes.beforeWhitespace', "Autoclose quotes only when the cursor is to the left of whitespace."), - '', - ], - 'default': EDITOR_DEFAULTS.autoClosingQuotes, - 'description': nls.localize('autoClosingQuotes', "Controls whether the editor should automatically close quotes after the user adds an opening quote.") - }, - 'editor.autoClosingOvertype': { - type: 'string', - enum: ['always', 'auto', 'never'], - enumDescriptions: [ - nls.localize('editor.autoClosingOvertype.always', "Always type over closing quotes or brackets."), - nls.localize('editor.autoClosingOvertype.auto', "Type over closing quotes or brackets only if they were automatically inserted."), - nls.localize('editor.autoClosingOvertype.never', "Never type over closing quotes or brackets."), - ], - 'default': EDITOR_DEFAULTS.autoClosingOvertype, - 'description': nls.localize('autoClosingOvertype', "Controls whether the editor should type over closing quotes or brackets.") - }, - 'editor.autoSurround': { - type: 'string', - enum: ['languageDefined', 'brackets', 'quotes', 'never'], - enumDescriptions: [ - nls.localize('editor.autoSurround.languageDefined', "Use language configurations to determine when to automatically surround selections."), - nls.localize('editor.autoSurround.brackets', "Surround with brackets but not quotes."), - nls.localize('editor.autoSurround.quotes', "Surround with quotes but not brackets."), - '' - ], - 'default': EDITOR_DEFAULTS.autoSurround, - 'description': nls.localize('autoSurround', "Controls whether the editor should automatically surround selections.") - }, - 'editor.formatOnType': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.formatOnType, - 'description': nls.localize('formatOnType', "Controls whether the editor should automatically format the line after typing.") - }, - 'editor.formatOnPaste': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.formatOnPaste, - 'description': nls.localize('formatOnPaste', "Controls whether the editor should automatically format the pasted content. A formatter must be available and the formatter should be able to format a range in a document.") - }, - 'editor.autoIndent': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.autoIndent, - 'description': nls.localize('autoIndent', "Controls whether the editor should automatically adjust the indentation when users type, paste or move lines. Extensions with indentation rules of the language must be available.") - }, - 'editor.suggestOnTriggerCharacters': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.suggestOnTriggerCharacters, - 'description': nls.localize('suggestOnTriggerCharacters', "Controls whether suggestions should automatically show up when typing trigger characters.") - }, - 'editor.acceptSuggestionOnEnter': { - 'type': 'string', - 'enum': ['on', 'smart', 'off'], - 'default': EDITOR_DEFAULTS.contribInfo.acceptSuggestionOnEnter, - 'markdownEnumDescriptions': [ - '', - nls.localize('acceptSuggestionOnEnterSmart', "Only accept a suggestion with `Enter` when it makes a textual change."), - '' - ], - 'markdownDescription': nls.localize('acceptSuggestionOnEnter', "Controls whether suggestions should be accepted on `Enter`, in addition to `Tab`. Helps to avoid ambiguity between inserting new lines or accepting suggestions.") - }, - 'editor.acceptSuggestionOnCommitCharacter': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.acceptSuggestionOnCommitCharacter, - 'markdownDescription': nls.localize('acceptSuggestionOnCommitCharacter', "Controls whether suggestions should be accepted on commit characters. For example, in JavaScript, the semi-colon (`;`) can be a commit character that accepts a suggestion and types that character.") - }, - 'editor.snippetSuggestions': { - 'type': 'string', - 'enum': ['top', 'bottom', 'inline', 'none'], - 'enumDescriptions': [ - nls.localize('snippetSuggestions.top', "Show snippet suggestions on top of other suggestions."), - nls.localize('snippetSuggestions.bottom', "Show snippet suggestions below other suggestions."), - nls.localize('snippetSuggestions.inline', "Show snippets suggestions with other suggestions."), - nls.localize('snippetSuggestions.none', "Do not show snippet suggestions."), - ], - 'default': EDITOR_DEFAULTS.contribInfo.suggest.snippets, - 'description': nls.localize('snippetSuggestions', "Controls whether snippets are shown with other suggestions and how they are sorted.") - }, - 'editor.emptySelectionClipboard': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.emptySelectionClipboard, - 'description': nls.localize('emptySelectionClipboard', "Controls whether copying without a selection copies the current line.") - }, - 'editor.copyWithSyntaxHighlighting': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.copyWithSyntaxHighlighting, - 'description': nls.localize('copyWithSyntaxHighlighting', "Controls whether syntax highlighting should be copied into the clipboard.") - }, - 'editor.wordBasedSuggestions': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.wordBasedSuggestions, - 'description': nls.localize('wordBasedSuggestions', "Controls whether completions should be computed based on words in the document.") - }, - 'editor.suggestSelection': { - 'type': 'string', - 'enum': ['first', 'recentlyUsed', 'recentlyUsedByPrefix'], - 'markdownEnumDescriptions': [ - nls.localize('suggestSelection.first', "Always select the first suggestion."), - nls.localize('suggestSelection.recentlyUsed', "Select recent suggestions unless further typing selects one, e.g. `console.| -> console.log` because `log` has been completed recently."), - nls.localize('suggestSelection.recentlyUsedByPrefix', "Select suggestions based on previous prefixes that have completed those suggestions, e.g. `co -> console` and `con -> const`."), - ], - 'default': 'recentlyUsed', - 'description': nls.localize('suggestSelection', "Controls how suggestions are pre-selected when showing the suggest list.") - }, - 'editor.suggestFontSize': { - 'type': 'integer', - 'default': 0, - 'minimum': 0, - 'markdownDescription': nls.localize('suggestFontSize', "Font size for the suggest widget. When set to `0`, the value of `#editor.fontSize#` is used.") - }, - 'editor.suggestLineHeight': { - 'type': 'integer', - 'default': 0, - 'minimum': 0, - 'markdownDescription': nls.localize('suggestLineHeight', "Line height for the suggest widget. When set to `0`, the value of `#editor.lineHeight#` is used.") - }, - 'editor.tabCompletion': { - type: 'string', - default: 'off', - enum: ['on', 'off', 'onlySnippets'], - enumDescriptions: [ - nls.localize('tabCompletion.on', "Tab complete will insert the best matching suggestion when pressing tab."), - nls.localize('tabCompletion.off', "Disable tab completions."), - nls.localize('tabCompletion.onlySnippets', "Tab complete snippets when their prefix match. Works best when 'quickSuggestions' aren't enabled."), - ], - description: nls.localize('tabCompletion', "Enables tab completions.") - }, - 'editor.suggest.filterGraceful': { type: 'boolean', - default: true, - description: nls.localize('suggest.filterGraceful', "Controls whether filtering and sorting suggestions accounts for small typos.") - }, - 'editor.suggest.localityBonus': { - type: 'boolean', - default: false, - description: nls.localize('suggest.localityBonus', "Controls whether sorting favours words that appear close to the cursor.") - }, - 'editor.suggest.shareSuggestSelections': { - type: 'boolean', - default: false, - markdownDescription: nls.localize('suggest.shareSuggestSelections', "Controls whether remembered suggestion selections are shared between multiple workspaces and windows (needs `#editor.suggestSelection#`).") - }, - 'editor.suggest.snippetsPreventQuickSuggestions': { - type: 'boolean', - default: true, - description: nls.localize('suggest.snippetsPreventQuickSuggestions', "Control whether an active snippet prevents quick suggestions.") - }, - 'editor.suggest.showIcons': { - type: 'boolean', - default: EDITOR_DEFAULTS.contribInfo.suggest.showIcons, - description: nls.localize('suggest.showIcons', "Controls whether to show or hide icons in suggestions.") - }, - 'editor.suggest.maxVisibleSuggestions': { - type: 'number', - default: EDITOR_DEFAULTS.contribInfo.suggest.maxVisibleSuggestions, - minimum: 1, - maximum: 15, - description: nls.localize('suggest.maxVisibleSuggestions', "Controls how many suggestions IntelliSense will show before showing a scrollbar (maximum 15).") - }, - 'editor.suggest.filteredTypes': { - type: 'object', - 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: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.method', "When set to `false` IntelliSense never shows `method` suggestions.") - }, - function: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.function', "When set to `false` IntelliSense never shows `function` suggestions.") - }, - constructor: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.constructor', "When set to `false` IntelliSense never shows `constructor` suggestions.") - }, - field: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.field', "When set to `false` IntelliSense never shows `field` suggestions.") - }, - variable: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.variable', "When set to `false` IntelliSense never shows `variable` suggestions.") - }, - class: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.class', "When set to `false` IntelliSense never shows `class` suggestions.") - }, - struct: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.struct', "When set to `false` IntelliSense never shows `struct` suggestions.") - }, - interface: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.interface', "When set to `false` IntelliSense never shows `interface` suggestions.") - }, - module: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.module', "When set to `false` IntelliSense never shows `module` suggestions.") - }, - property: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.property', "When set to `false` IntelliSense never shows `property` suggestions.") - }, - event: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.event', "When set to `false` IntelliSense never shows `event` suggestions.") - }, - operator: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.operator', "When set to `false` IntelliSense never shows `operator` suggestions.") - }, - unit: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.unit', "When set to `false` IntelliSense never shows `unit` suggestions.") - }, - value: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.value', "When set to `false` IntelliSense never shows `value` suggestions.") - }, - constant: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.constant', "When set to `false` IntelliSense never shows `constant` suggestions.") - }, - enum: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.enum', "When set to `false` IntelliSense never shows `enum` suggestions.") - }, - enumMember: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.enumMember', "When set to `false` IntelliSense never shows `enumMember` suggestions.") - }, - keyword: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.keyword', "When set to `false` IntelliSense never shows `keyword` suggestions.") - }, - text: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.text', "When set to `false` IntelliSense never shows `text` suggestions.") - }, - color: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.color', "When set to `false` IntelliSense never shows `color` suggestions.") - }, - file: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.file', "When set to `false` IntelliSense never shows `file` suggestions.") - }, - reference: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.reference', "When set to `false` IntelliSense never shows `reference` suggestions.") - }, - customcolor: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.customcolor', "When set to `false` IntelliSense never shows `customcolor` suggestions.") - }, - folder: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.folder', "When set to `false` IntelliSense never shows `folder` suggestions.") - }, - typeParameter: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.typeParameter', "When set to `false` IntelliSense never shows `typeParameter` suggestions.") - }, - snippet: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.snippet', "When set to `false` IntelliSense never shows `snippet` suggestions.") - }, - } - }, - 'editor.gotoLocation.multiple': { - description: nls.localize('editor.gotoLocation.multiple', "Controls the behavior of 'Go To' commands, like Go To Definition, when multiple target locations exist."), - type: 'string', - enum: ['peek', 'gotoAndPeek', 'goto'], - default: EDITOR_DEFAULTS.contribInfo.gotoLocation.multiple, - enumDescriptions: [ - nls.localize('editor.gotoLocation.multiple.peek', 'Show peek view of the results (default)'), - nls.localize('editor.gotoLocation.multiple.gotoAndPeek', 'Go to the primary result and show a peek view'), - nls.localize('editor.gotoLocation.multiple.goto', 'Go to the primary result and enable peek-less navigation to others') - ] - }, - 'editor.selectionHighlight': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.selectionHighlight, - 'description': nls.localize('selectionHighlight', "Controls whether the editor should highlight matches similar to the selection.") - }, - 'editor.occurrencesHighlight': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.occurrencesHighlight, - 'description': nls.localize('occurrencesHighlight', "Controls whether the editor should highlight semantic symbol occurrences.") - }, - 'editor.overviewRulerLanes': { - 'type': 'integer', - 'default': 3, - 'description': nls.localize('overviewRulerLanes', "Controls the number of decorations that can show up at the same position in the overview ruler.") - }, - 'editor.overviewRulerBorder': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.overviewRulerBorder, - 'description': nls.localize('overviewRulerBorder', "Controls whether a border should be drawn around the overview ruler.") - }, - 'editor.cursorBlinking': { - 'type': 'string', - 'enum': ['blink', 'smooth', 'phase', 'expand', 'solid'], - 'default': editorOptions.blinkingStyleToString(EDITOR_DEFAULTS.viewInfo.cursorBlinking), - 'description': nls.localize('cursorBlinking', "Control the cursor animation style.") - }, - 'editor.mouseWheelZoom': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.mouseWheelZoom, - 'markdownDescription': nls.localize('mouseWheelZoom', "Zoom the font of the editor when using mouse wheel and holding `Ctrl`.") - }, - 'editor.cursorSmoothCaretAnimation': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.cursorSmoothCaretAnimation, - 'description': nls.localize('cursorSmoothCaretAnimation', "Controls whether the smooth caret animation should be enabled.") - }, - 'editor.cursorStyle': { - 'type': 'string', - 'enum': ['block', 'block-outline', 'line', 'line-thin', 'underline', 'underline-thin'], - 'default': editorOptions.cursorStyleToString(EDITOR_DEFAULTS.viewInfo.cursorStyle), - 'description': nls.localize('cursorStyle', "Controls the cursor style.") - }, - 'editor.cursorWidth': { - 'type': 'integer', - 'default': EDITOR_DEFAULTS.viewInfo.cursorWidth, - 'markdownDescription': nls.localize('cursorWidth', "Controls the width of the cursor when `#editor.cursorStyle#` is set to `line`.") - }, - 'editor.fontLigatures': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.fontLigatures, - 'description': nls.localize('fontLigatures', "Enables/Disables font ligatures.") - }, - 'editor.hideCursorInOverviewRuler': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.hideCursorInOverviewRuler, - 'description': nls.localize('hideCursorInOverviewRuler', "Controls whether the cursor should be hidden in the overview ruler.") - }, - 'editor.renderWhitespace': { - 'type': 'string', - 'enum': ['none', 'boundary', 'selection', 'all'], - 'enumDescriptions': [ - '', - nls.localize('renderWhitespace.boundary', "Render whitespace characters except for single spaces between words."), - nls.localize('renderWhitespace.selection', "Render whitespace characters only on selected text."), - '' - ], - default: EDITOR_DEFAULTS.viewInfo.renderWhitespace, - description: nls.localize('renderWhitespace', "Controls how the editor should render whitespace characters.") - }, - 'editor.renderControlCharacters': { - 'type': 'boolean', - default: EDITOR_DEFAULTS.viewInfo.renderControlCharacters, - description: nls.localize('renderControlCharacters', "Controls whether the editor should render control characters.") - }, - 'editor.renderIndentGuides': { - 'type': 'boolean', - default: EDITOR_DEFAULTS.viewInfo.renderIndentGuides, - description: nls.localize('renderIndentGuides', "Controls whether the editor should render indent guides.") - }, - 'editor.highlightActiveIndentGuide': { - 'type': 'boolean', - default: EDITOR_DEFAULTS.viewInfo.highlightActiveIndentGuide, - description: nls.localize('highlightActiveIndentGuide', "Controls whether the editor should highlight the active indent guide.") - }, - 'editor.renderLineHighlight': { - 'type': 'string', - 'enum': ['none', 'gutter', 'line', 'all'], - 'enumDescriptions': [ - '', - '', - '', - nls.localize('renderLineHighlight.all', "Highlights both the gutter and the current line."), - ], - default: EDITOR_DEFAULTS.viewInfo.renderLineHighlight, - description: nls.localize('renderLineHighlight', "Controls how the editor should render the current line highlight.") - }, - 'editor.codeLens': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.codeLens, - 'description': nls.localize('codeLens', "Controls whether the editor shows CodeLens.") - }, - 'editor.folding': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.folding, - 'description': nls.localize('folding', "Controls whether the editor has code folding enabled.") - }, - 'editor.foldingStrategy': { - 'type': 'string', - 'enum': ['auto', 'indentation'], - 'default': EDITOR_DEFAULTS.contribInfo.foldingStrategy, - 'markdownDescription': nls.localize('foldingStrategy', "Controls the strategy for computing folding ranges. `auto` uses a language specific folding strategy, if available. `indentation` uses the indentation based folding strategy.") - }, - 'editor.showFoldingControls': { - 'type': 'string', - 'enum': ['always', 'mouseover'], - 'default': EDITOR_DEFAULTS.contribInfo.showFoldingControls, - 'description': nls.localize('showFoldingControls', "Controls whether the fold controls on the gutter are automatically hidden.") - }, - 'editor.matchBrackets': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.matchBrackets, - 'description': nls.localize('matchBrackets', "Highlight matching brackets when one of them is selected.") - }, - 'editor.glyphMargin': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.glyphMargin, - 'description': nls.localize('glyphMargin', "Controls whether the editor should render the vertical glyph margin. Glyph margin is mostly used for debugging.") - }, - 'editor.useTabStops': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.useTabStops, - 'description': nls.localize('useTabStops', "Inserting and deleting whitespace follows tab stops.") + default: EDITOR_MODEL_DEFAULTS.detectIndentation, + markdownDescription: nls.localize('detectIndentation', "Controls whether `#editor.tabSize#` and `#editor.insertSpaces#` will be automatically detected when a file is opened based on the file contents.") }, 'editor.trimAutoWhitespace': { - 'type': 'boolean', - 'default': EDITOR_MODEL_DEFAULTS.trimAutoWhitespace, - 'description': nls.localize('trimAutoWhitespace', "Remove trailing auto inserted whitespace.") + type: 'boolean', + default: EDITOR_MODEL_DEFAULTS.trimAutoWhitespace, + description: nls.localize('trimAutoWhitespace', "Remove trailing auto inserted whitespace.") + }, + 'editor.largeFileOptimizations': { + type: 'boolean', + default: EDITOR_MODEL_DEFAULTS.largeFileOptimizations, + description: nls.localize('largeFileOptimizations', "Special handling for large files to disable certain memory intensive features.") + }, + 'editor.wordBasedSuggestions': { + type: 'boolean', + default: true, + description: nls.localize('wordBasedSuggestions', "Controls whether completions should be computed based on words in the document.") }, 'editor.stablePeek': { - 'type': 'boolean', - 'default': false, - 'markdownDescription': nls.localize('stablePeek', "Keep peek editors open even when double clicking their content or when hitting `Escape`.") - }, - 'editor.dragAndDrop': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.dragAndDrop, - 'description': nls.localize('dragAndDrop', "Controls whether the editor should allow moving selections via drag and drop.") - }, - 'editor.accessibilitySupport': { - 'type': 'string', - 'enum': ['auto', 'on', 'off'], - 'enumDescriptions': [ - nls.localize('accessibilitySupport.auto', "The editor will use platform APIs to detect when a Screen Reader is attached."), - nls.localize('accessibilitySupport.on', "The editor will be permanently optimized for usage with a Screen Reader."), - nls.localize('accessibilitySupport.off', "The editor will never be optimized for usage with a Screen Reader."), - ], - 'default': EDITOR_DEFAULTS.accessibilitySupport, - 'description': nls.localize('accessibilitySupport', "Controls whether the editor should run in a mode where it is optimized for screen readers.") - }, - 'editor.showUnused': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.showUnused, - 'description': nls.localize('showUnused', "Controls fading out of unused code.") - }, - 'editor.links': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.links, - 'description': nls.localize('links', "Controls whether the editor should detect links and make them clickable.") - }, - 'editor.colorDecorators': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.colorDecorators, - 'description': nls.localize('colorDecorators', "Controls whether the editor should render the inline color decorators and color picker.") - }, - 'editor.lightbulb.enabled': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.lightbulbEnabled, - 'description': nls.localize('codeActions', "Enables the code action lightbulb in the editor.") + type: 'boolean', + default: false, + markdownDescription: nls.localize('stablePeek', "Keep peek editors open even when double clicking their content or when hitting `Escape`.") }, 'editor.maxTokenizationLineLength': { - 'type': 'integer', - 'default': 20_000, - 'description': nls.localize('maxTokenizationLineLength', "Lines above this length will not be tokenized for performance reasons") + type: 'integer', + default: 20_000, + description: nls.localize('maxTokenizationLineLength', "Lines above this length will not be tokenized for performance reasons") }, 'editor.codeActionsOnSave': { - 'type': 'object', - 'properties': { + type: 'object', + properties: { 'source.organizeImports': { - 'type': 'boolean', - 'description': nls.localize('codeActionsOnSave.organizeImports', "Controls whether organize imports action should be run on file save.") + type: 'boolean', + description: nls.localize('codeActionsOnSave.organizeImports', "Controls whether organize imports action should be run on file save.") }, 'source.fixAll': { - 'type': 'boolean', - 'description': nls.localize('codeActionsOnSave.fixAll', "Controls whether auto fix action should be run on file save.") + type: 'boolean', + description: nls.localize('codeActionsOnSave.fixAll', "Controls whether auto fix action should be run on file save.") } }, 'additionalProperties': { - 'type': 'boolean' + type: 'boolean' }, - 'default': EDITOR_DEFAULTS.contribInfo.codeActionsOnSave, - 'description': nls.localize('codeActionsOnSave', "Code action kinds to be run on save.") + default: {}, + description: nls.localize('codeActionsOnSave', "Code action kinds to be run on save.") }, 'editor.codeActionsOnSaveTimeout': { - 'type': 'number', - 'default': EDITOR_DEFAULTS.contribInfo.codeActionsOnSaveTimeout, - 'description': nls.localize('codeActionsOnSaveTimeout', "Timeout in milliseconds after which the code actions that are run on save are cancelled.") - }, - 'editor.selectionClipboard': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.selectionClipboard, - 'description': nls.localize('selectionClipboard', "Controls whether the Linux primary clipboard should be supported."), - 'included': platform.isLinux + type: 'number', + default: 750, + description: nls.localize('codeActionsOnSaveTimeout', "Timeout in milliseconds after which the code actions that are run on save are cancelled.") }, 'diffEditor.renderSideBySide': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('sideBySide', "Controls whether the diff editor shows the diff side by side or inline.") + type: 'boolean', + default: true, + description: nls.localize('sideBySide', "Controls whether the diff editor shows the diff side by side or inline.") }, 'diffEditor.ignoreTrimWhitespace': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('ignoreTrimWhitespace', "Controls whether the diff editor shows changes in leading or trailing whitespace as diffs.") - }, - 'editor.largeFileOptimizations': { - 'type': 'boolean', - 'default': EDITOR_MODEL_DEFAULTS.largeFileOptimizations, - 'description': nls.localize('largeFileOptimizations', "Special handling for large files to disable certain memory intensive features.") + type: 'boolean', + default: true, + description: nls.localize('ignoreTrimWhitespace', "Controls whether the diff editor shows changes in leading or trailing whitespace as diffs.") }, 'diffEditor.renderIndicators': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('renderIndicators', "Controls whether the diff editor shows +/- indicators for added/removed changes.") + type: 'boolean', + default: true, + description: nls.localize('renderIndicators', "Controls whether the diff editor shows +/- indicators for added/removed changes.") } } }; +function isConfigurationPropertySchema(x: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema; }): x is IConfigurationPropertySchema { + return (typeof x.type !== 'undefined' || typeof x.anyOf !== 'undefined'); +} + +// Add properties from the Editor Option Registry +for (const editorOption of editorOptionsRegistry) { + const schema = editorOption.schema; + if (typeof schema !== 'undefined') { + if (isConfigurationPropertySchema(schema)) { + // This is a single schema contribution + editorConfiguration.properties![`editor.${editorOption.name}`] = schema; + } else { + for (let key in schema) { + if (hasOwnProperty.call(schema, key)) { + editorConfiguration.properties![key] = schema[key]; + } + } + } + } +} + let cachedEditorConfigurationKeys: { [key: string]: boolean; } | null = null; function getEditorConfigurationKeys(): { [key: string]: boolean; } { if (cachedEditorConfigurationKeys === null) { diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 7b731eb3d3..139141fa31 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import * as arrays from 'vs/base/common/arrays'; -import * as objects from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { FontInfo } from 'vs/editor/common/config/fontInfo'; @@ -13,90 +11,9 @@ import { Constants } from 'vs/editor/common/core/uint'; import { USUAL_WORD_SEPARATORS } from 'vs/editor/common/model/wordHelper'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { isObject } from 'vs/base/common/types'; +import { IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry'; -/** - * Configuration options for editor scrollbars - */ -export interface IEditorScrollbarOptions { - /** - * The size of arrows (if displayed). - * Defaults to 11. - */ - arrowSize?: number; - /** - * Render vertical scrollbar. - * Defaults to 'auto'. - */ - vertical?: 'auto' | 'visible' | 'hidden'; - /** - * Render horizontal scrollbar. - * Defaults to 'auto'. - */ - horizontal?: 'auto' | 'visible' | 'hidden'; - /** - * Cast horizontal and vertical shadows when the content is scrolled. - * Defaults to true. - */ - useShadows?: boolean; - /** - * Render arrows at the top and bottom of the vertical scrollbar. - * Defaults to false. - */ - verticalHasArrows?: boolean; - /** - * Render arrows at the left and right of the horizontal scrollbar. - * Defaults to false. - */ - horizontalHasArrows?: boolean; - /** - * Listen to mouse wheel events and react to them by scrolling. - * Defaults to true. - */ - handleMouseWheel?: boolean; - /** - * Height in pixels for the horizontal scrollbar. - * Defaults to 10 (px). - */ - horizontalScrollbarSize?: number; - /** - * Width in pixels for the vertical scrollbar. - * Defaults to 10 (px). - */ - verticalScrollbarSize?: number; - /** - * Width in pixels for the vertical slider. - * Defaults to `verticalScrollbarSize`. - */ - verticalSliderSize?: number; - /** - * Height in pixels for the horizontal slider. - * Defaults to `horizontalScrollbarSize`. - */ - horizontalSliderSize?: number; -} - -/** - * Configuration options for editor find widget - */ -export interface IEditorFindOptions { - /** - * Controls if we seed search string in the Find Widget with editor selection. - */ - seedSearchStringFromSelection?: boolean; - /** - * Controls if Find in Selection flag is turned on when multiple lines of text are selected in the editor. - */ - autoFindInSelection: boolean; - /* - * Controls whether the Find Widget should add extra lines on top of the editor. - */ - addExtraSpaceOnTop?: boolean; - /** - * @internal - * Controls if the Find Widget should read or modify the shared find clipboard on macOS - */ - globalFindClipboard: boolean; -} +//#region typed options /** * Configuration options for auto closing quotes and brackets @@ -113,137 +30,12 @@ export type EditorAutoSurroundStrategy = 'languageDefined' | 'quotes' | 'bracket */ export type EditorAutoClosingOvertypeStrategy = 'always' | 'auto' | 'never'; -/** - * Configuration options for editor minimap - */ -export interface IEditorMinimapOptions { - /** - * Enable the rendering of the minimap. - * Defaults to true. - */ - enabled?: boolean; - /** - * Control the side of the minimap in editor. - * Defaults to 'right'. - */ - side?: 'right' | 'left'; - /** - * Control the rendering of the minimap slider. - * Defaults to 'mouseover'. - */ - showSlider?: 'always' | 'mouseover'; - /** - * Render the actual text on a line (as opposed to color blocks). - * Defaults to true. - */ - renderCharacters?: boolean; - /** - * Limit the width of the minimap to render at most a certain number of columns. - * Defaults to 120. - */ - maxColumn?: number; -} - -/** - * Configuration options for editor minimap - */ -export interface IEditorLightbulbOptions { - /** - * Enable the lightbulb code action. - * Defaults to true. - */ - enabled?: boolean; -} - -/** - * Configuration options for editor hover - */ -export interface IEditorHoverOptions { - /** - * Enable the hover. - * Defaults to true. - */ - enabled?: boolean; - /** - * Delay for showing the hover. - * Defaults to 300. - */ - delay?: number; - /** - * Is the hover sticky such that it can be clicked and its contents selected? - * Defaults to true. - */ - sticky?: boolean; -} - -/** - * Configuration options for parameter hints - */ -export interface IEditorParameterHintOptions { - /** - * Enable parameter hints. - * Defaults to true. - */ - enabled?: boolean; - /** - * Enable cycling of parameter hints. - * Defaults to false. - */ - cycle?: boolean; -} - -export interface ISuggestOptions { - /** - * Enable graceful matching. Defaults to true. - */ - filterGraceful?: boolean; - /** - * Prevent quick suggestions when a snippet is active. Defaults to true. - */ - snippetsPreventQuickSuggestions?: boolean; - /** - * Favours words that appear close to the cursor. - */ - localityBonus?: boolean; - /** - * Enable using global storage for remembering suggestions. - */ - shareSuggestSelections?: boolean; - /** - * Enable or disable icons in suggestions. Defaults to true. - */ - showIcons?: boolean; - /** - * Max suggestions to show in suggestions. Defaults to 12. - */ - maxVisibleSuggestions?: boolean; - /** - * Names of suggestion types to filter. - */ - filteredTypes?: Record; -} - -export interface IGotoLocationOptions { - /** - * Control how goto-command work when having multiple results. - */ - multiple?: 'peek' | 'gotoAndPeek' | 'goto'; -} - -/** - * Configuration map for codeActionsOnSave - */ -export interface ICodeActionsOnSaveOptions { - [kind: string]: boolean; -} - /** * Configuration options for the editor. */ export interface IEditorOptions { /** * This editor is used inside a diff editor. - * @internal */ inDiffEditor?: boolean; /** @@ -272,7 +64,7 @@ export interface IEditorOptions { * Otherwise, line numbers will not be rendered. * Defaults to true. */ - lineNumbers?: 'on' | 'off' | 'relative' | 'interval' | ((lineNumber: number) => string); + lineNumbers?: LineNumbersType; /** * Controls the minimal number of visible leading and trailing lines surrounding the cursor. * Defaults to 0. @@ -356,7 +148,7 @@ export interface IEditorOptions { * Control the cursor animation style, possible values are 'blink', 'smooth', 'phase', 'expand' and 'solid'. * Defaults to 'blink'. */ - cursorBlinking?: string; + cursorBlinking?: 'blink' | 'smooth' | 'phase' | 'expand' | 'solid'; /** * Zoom the font in the editor when using the mouse wheel in combination with holding Ctrl. * Defaults to false. @@ -365,7 +157,6 @@ export interface IEditorOptions { /** * Control the mouse pointer style, either 'text' or 'default' or 'copy' * Defaults to 'text' - * @internal */ mouseStyle?: 'text' | 'default' | 'copy'; /** @@ -377,7 +168,7 @@ export interface IEditorOptions { * Control the cursor style, either 'block' or 'line'. * Defaults to 'line'. */ - cursorStyle?: string; + cursorStyle?: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin'; /** * Control the width of the cursor when cursorStyle is set to 'line' */ @@ -451,7 +242,7 @@ export interface IEditorOptions { * Control indentation of wrapped lines. Can be: 'none', 'same', 'indent' or 'deepIndent'. * Defaults to 'same' in vscode and to 'none' in monaco-editor. */ - wrappingIndent?: string; + wrappingIndent?: 'none' | 'same' | 'indent' | 'deepIndent'; /** * Configure word wrapping characters. A break will be introduced before these characters. * Defaults to '{([+'. @@ -467,7 +258,6 @@ export interface IEditorOptions { * Defaults to '.'. */ wordWrapBreakObtrusiveCharacters?: string; - /** * Performance guard: Stop rendering a line after x characters. * Defaults to 10000. @@ -512,6 +302,11 @@ export interface IEditorOptions { * Defaults to true */ multiCursorMergeOverlapping?: boolean; + /** + * Configure the behaviour when pasting a text with the line count equal to the cursor count. + * Defaults to 'spread'. + */ + multiCursorPaste?: 'spread' | 'full'; /** * Configure the editor's accessibility support. * Defaults to 'auto'. It is best to leave this to 'auto'. @@ -529,10 +324,10 @@ export interface IEditorOptions { * Enable quick suggestions (shadow suggestions) * Defaults to true. */ - quickSuggestions?: boolean | { other: boolean, comments: boolean, strings: boolean }; + quickSuggestions?: boolean | IQuickSuggestionsOptions; /** * Quick suggestions show delay (in ms) - * Defaults to 500 (ms) + * Defaults to 10 (ms) */ quickSuggestionsDelay?: number; /** @@ -587,7 +382,7 @@ export interface IEditorOptions { * Accept suggestions on ENTER. * Defaults to 'on'. */ - acceptSuggestionOnEnter?: boolean | 'on' | 'smart' | 'off'; + acceptSuggestionOnEnter?: 'on' | 'smart' | 'off'; /** * Accept suggestions on provider defined characters. * Defaults to true. @@ -605,10 +400,6 @@ export interface IEditorOptions { * Syntax highlighting is copied. */ copyWithSyntaxHighlighting?: boolean; - /** - * Enable word based suggestions. Defaults to 'true' - */ - wordBasedSuggestions?: boolean; /** * The history mode for suggestions. */ @@ -626,7 +417,7 @@ export interface IEditorOptions { /** * Enable tab completion. */ - tabCompletion?: boolean | 'on' | 'off' | 'onlySnippets'; + tabCompletion?: 'on' | 'off' | 'onlySnippets'; /** * Enable selection highlight. * Defaults to true. @@ -646,10 +437,6 @@ export interface IEditorOptions { * Control the behavior and rendering of the code action lightbulb. */ lightbulb?: IEditorLightbulbOptions; - /** - * Code action kinds to be run on save. - */ - codeActionsOnSave?: ICodeActionsOnSaveOptions; /** * Timeout for running code actions on save. */ @@ -710,7 +497,7 @@ export interface IEditorOptions { /** * The font weight */ - fontWeight?: 'normal' | 'bold' | 'bolder' | 'lighter' | 'initial' | 'inherit' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; + fontWeight?: string; /** * The font size */ @@ -766,36 +553,389 @@ export interface IDiffEditorOptions extends IEditorOptions { reverse?: boolean; } -export const enum RenderMinimap { - None = 0, - Small = 1, - Large = 2, - SmallBlocks = 3, - LargeBlocks = 4, +//#endregion + +/** + * An event describing that the configuration of the editor has changed. + */ +export class ConfigurationChangedEvent { + private readonly _values: boolean[]; + /** + * @internal + */ + constructor(values: boolean[]) { + this._values = values; + } + /** + * @internal + */ + public hasChanged(id: EditorOption): boolean { + return this._values[id]; + } } /** - * Describes how to indent wrapped lines. + * @internal */ -export const enum WrappingIndent { - /** - * No indentation => wrapped lines begin at column 1. - */ - None = 0, - /** - * Same => wrapped lines get the same indentation as the parent. - */ - Same = 1, - /** - * Indent => wrapped lines get +1 indentation toward the parent. - */ - Indent = 2, - /** - * DeepIndent => wrapped lines get +2 indentation toward the parent. - */ - DeepIndent = 3 +export class ValidatedEditorOptions { + private readonly _values: any[] = []; + public _read(option: EditorOption): T { + return this._values[option]; + } + public get(id: T): FindComputedEditorOptionValueById { + return this._values[id]; + } + public _write(option: EditorOption, value: T): void { + this._values[option] = value; + } } +/** + * @internal + */ +export interface IComputedEditorOptions { + get(id: T): FindComputedEditorOptionValueById; +} + +//#region IEditorOption + +/** + * @internal + */ +export interface IEnvironmentalOptions { + readonly outerWidth: number; + readonly outerHeight: number; + readonly fontInfo: FontInfo; + readonly extraEditorClassName: string; + readonly isDominatedByLongLines: boolean; + readonly lineNumbersDigitCount: number; + readonly emptySelectionClipboard: boolean; + readonly pixelRatio: number; + readonly tabFocusMode: boolean; + readonly accessibilitySupport: AccessibilitySupport; +} + +/** + * @internal + */ +export interface IEditorOption { + readonly id: K1; + readonly name: string; + readonly defaultValue: V; + /** + * @internal + */ + readonly schema: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema; } | undefined; + /** + * @internal + */ + validate(input: any): V; + /** + * @internal + */ + compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V; +} + +type PossibleKeyName0 = { [K in keyof IEditorOptions]: IEditorOptions[K] extends V | undefined ? K : never }[keyof IEditorOptions]; +type PossibleKeyName = NonNullable>; + +abstract class BaseEditorOption implements IEditorOption { + + public readonly id: K1; + public readonly name: string; + public readonly defaultValue: V; + public readonly schema: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema; } | undefined; + + constructor(id: K1, name: string, defaultValue: V, schema?: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema; }) { + this.id = id; + this.name = name; + this.defaultValue = defaultValue; + this.schema = schema; + } + + public abstract validate(input: any): V; + + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V { + return value; + } +} + +/** + * @internal + */ +abstract class ComputedEditorOption implements IEditorOption { + + public readonly id: K1; + public readonly name: '_never_'; + public readonly defaultValue: V; + public readonly deps: EditorOption[] | null; + public readonly schema: IConfigurationPropertySchema | undefined = undefined; + + constructor(id: K1, deps: EditorOption[] | null = null) { + this.id = id; + this.name = '_never_'; + this.defaultValue = undefined; + this.deps = deps; + } + + public validate(input: any): V { + return this.defaultValue; + } + + public abstract compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V; +} + +class SimpleEditorOption implements IEditorOption { + + public readonly id: K1; + public readonly name: PossibleKeyName; + public readonly defaultValue: V; + public readonly schema: IConfigurationPropertySchema | undefined; + + constructor(id: K1, name: PossibleKeyName, defaultValue: V, schema?: IConfigurationPropertySchema) { + this.id = id; + this.name = name; + this.defaultValue = defaultValue; + this.schema = schema; + } + + public validate(input: any): V { + if (typeof input === 'undefined') { + return this.defaultValue; + } + return input as any; + } + + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V { + return value; + } +} + +class EditorBooleanOption extends SimpleEditorOption { + + public static boolean(value: any, defaultValue: boolean): boolean { + if (typeof value === 'undefined') { + return defaultValue; + } + if (value === 'false') { + // treat the string 'false' as false + return false; + } + return Boolean(value); + } + + constructor(id: K1, name: PossibleKeyName, defaultValue: boolean, schema: IConfigurationPropertySchema | undefined = undefined) { + if (typeof schema !== 'undefined') { + schema.type = 'boolean'; + schema.default = defaultValue; + } + super(id, name, defaultValue, schema); + } + + public validate(input: any): boolean { + return EditorBooleanOption.boolean(input, this.defaultValue); + } +} + +class EditorIntOption extends SimpleEditorOption { + + public static clampedInt(value: any, defaultValue: number, minimum: number, maximum: number): number { + let r: number; + if (typeof value === 'undefined') { + r = defaultValue; + } else { + r = parseInt(value, 10); + if (isNaN(r)) { + r = defaultValue; + } + } + r = Math.max(minimum, r); + r = Math.min(maximum, r); + return r | 0; + } + + public readonly minimum: number; + public readonly maximum: number; + + constructor(id: K1, name: PossibleKeyName, defaultValue: number, minimum: number, maximum: number, schema: IConfigurationPropertySchema | undefined = undefined) { + if (typeof schema !== 'undefined') { + schema.type = 'integer'; + schema.default = defaultValue; + schema.minimum = minimum; + schema.maximum = maximum; + } + super(id, name, defaultValue, schema); + this.minimum = minimum; + this.maximum = maximum; + } + + public validate(input: any): number { + return EditorIntOption.clampedInt(input, this.defaultValue, this.minimum, this.maximum); + } +} + +class EditorFloatOption extends SimpleEditorOption { + + public static clamp(n: number, min: number, max: number): number { + if (n < min) { + return min; + } + if (n > max) { + return max; + } + return n; + } + + public static float(value: any, defaultValue: number): number { + if (typeof value === 'number') { + return value; + } + if (typeof value === 'undefined') { + return defaultValue; + } + const r = parseFloat(value); + return (isNaN(r) ? defaultValue : r); + } + + public readonly validationFn: (value: number) => number; + + constructor(id: K1, name: PossibleKeyName, defaultValue: number, validationFn: (value: number) => number, schema?: IConfigurationPropertySchema) { + if (typeof schema !== 'undefined') { + schema.type = 'number'; + schema.default = defaultValue; + } + super(id, name, defaultValue, schema); + this.validationFn = validationFn; + } + + public validate(input: any): number { + return this.validationFn(EditorFloatOption.float(input, this.defaultValue)); + } +} + +class EditorStringOption extends SimpleEditorOption { + + public static string(value: any, defaultValue: string): string { + if (typeof value !== 'string') { + return defaultValue; + } + return value; + } + + constructor(id: K1, name: PossibleKeyName, defaultValue: string, schema: IConfigurationPropertySchema | undefined = undefined) { + if (typeof schema !== 'undefined') { + schema.type = 'string'; + schema.default = defaultValue; + } + super(id, name, defaultValue, schema); + } + + public validate(input: any): string { + return EditorStringOption.string(input, this.defaultValue); + } +} + +class EditorStringEnumOption extends SimpleEditorOption { + + public static stringSet(value: T | undefined, defaultValue: T, allowedValues: ReadonlyArray): T { + if (typeof value !== 'string') { + return defaultValue; + } + if (allowedValues.indexOf(value) === -1) { + return defaultValue; + } + return value; + } + + private readonly _allowedValues: ReadonlyArray; + + constructor(id: K1, name: PossibleKeyName, defaultValue: V, allowedValues: ReadonlyArray, schema: IConfigurationPropertySchema | undefined = undefined) { + if (typeof schema !== 'undefined') { + schema.type = 'string'; + schema.enum = allowedValues; + schema.default = defaultValue; + } + super(id, name, defaultValue, schema); + this._allowedValues = allowedValues; + } + + public validate(input: any): V { + return EditorStringEnumOption.stringSet(input, this.defaultValue, this._allowedValues); + } +} + +class EditorEnumOption extends BaseEditorOption { + + private readonly _allowedValues: T[]; + private readonly _convert: (value: T) => V; + + constructor(id: K1, name: PossibleKeyName, defaultValue: V, defaultStringValue: string, allowedValues: T[], convert: (value: T) => V, schema: IConfigurationPropertySchema | undefined = undefined) { + if (typeof schema !== 'undefined') { + schema.type = 'string'; + schema.enum = allowedValues; + schema.default = defaultStringValue; + } + super(id, name, defaultValue, schema); + this._allowedValues = allowedValues; + this._convert = convert; + } + + public validate(input: any): V { + if (typeof input !== 'string') { + return this.defaultValue; + } + if (this._allowedValues.indexOf(input) === -1) { + return this.defaultValue; + } + return this._convert(input); + } +} + +//#endregion + +//#region accessibilitySupport + +class EditorAccessibilitySupport extends BaseEditorOption { + + constructor() { + super( + EditorOption.accessibilitySupport, 'accessibilitySupport', AccessibilitySupport.Unknown, + { + type: 'string', + enum: ['auto', 'on', 'off'], + enumDescriptions: [ + nls.localize('accessibilitySupport.auto', "The editor will use platform APIs to detect when a Screen Reader is attached."), + nls.localize('accessibilitySupport.on', "The editor will be permanently optimized for usage with a Screen Reader."), + nls.localize('accessibilitySupport.off', "The editor will never be optimized for usage with a Screen Reader."), + ], + default: 'auto', + description: nls.localize('accessibilitySupport', "Controls whether the editor should run in a mode where it is optimized for screen readers.") + } + ); + } + + public validate(input: any): AccessibilitySupport { + switch (input) { + case 'auto': return AccessibilitySupport.Unknown; + case 'off': return AccessibilitySupport.Disabled; + case 'on': return AccessibilitySupport.Enabled; + } + return this.defaultValue; + } + + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: AccessibilitySupport): AccessibilitySupport { + if (value === AccessibilitySupport.Unknown) { + // The editor reads the `accessibilitySupport` from the environment + return env.accessibilitySupport; + } + return value; + } +} + +//#endregion + +//#region cursorBlinking + /** * The kind of animation in which the editor's cursor should be rendered. */ @@ -825,25 +965,21 @@ export const enum TextEditorCursorBlinkingStyle { */ Solid = 5 } -/** - * @internal - */ -export function blinkingStyleToString(blinkingStyle: TextEditorCursorBlinkingStyle): string { - if (blinkingStyle === TextEditorCursorBlinkingStyle.Blink) { - return 'blink'; - } else if (blinkingStyle === TextEditorCursorBlinkingStyle.Expand) { - return 'expand'; - } else if (blinkingStyle === TextEditorCursorBlinkingStyle.Phase) { - return 'phase'; - } else if (blinkingStyle === TextEditorCursorBlinkingStyle.Smooth) { - return 'smooth'; - } else if (blinkingStyle === TextEditorCursorBlinkingStyle.Solid) { - return 'solid'; - } else { - throw new Error('blinkingStyleToString: Unknown blinkingStyle'); + +function _cursorBlinkingStyleFromString(cursorBlinkingStyle: 'blink' | 'smooth' | 'phase' | 'expand' | 'solid'): TextEditorCursorBlinkingStyle { + switch (cursorBlinkingStyle) { + case 'blink': return TextEditorCursorBlinkingStyle.Blink; + case 'smooth': return TextEditorCursorBlinkingStyle.Smooth; + case 'phase': return TextEditorCursorBlinkingStyle.Phase; + case 'expand': return TextEditorCursorBlinkingStyle.Expand; + case 'solid': return TextEditorCursorBlinkingStyle.Solid; } } +//#endregion + +//#region cursorStyle + /** * The style in which the editor's cursor should be rendered. */ @@ -877,647 +1013,325 @@ export enum TextEditorCursorStyle { /** * @internal */ -export function cursorStyleToString(cursorStyle: TextEditorCursorStyle): string { - if (cursorStyle === TextEditorCursorStyle.Line) { - return 'line'; - } else if (cursorStyle === TextEditorCursorStyle.Block) { - return 'block'; - } else if (cursorStyle === TextEditorCursorStyle.Underline) { - return 'underline'; - } else if (cursorStyle === TextEditorCursorStyle.LineThin) { - return 'line-thin'; - } else if (cursorStyle === TextEditorCursorStyle.BlockOutline) { - return 'block-outline'; - } else if (cursorStyle === TextEditorCursorStyle.UnderlineThin) { - return 'underline-thin'; - } else { - throw new Error('cursorStyleToString: Unknown cursorStyle'); +export function cursorStyleToString(cursorStyle: TextEditorCursorStyle): 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin' { + switch (cursorStyle) { + case TextEditorCursorStyle.Line: return 'line'; + case TextEditorCursorStyle.Block: return 'block'; + case TextEditorCursorStyle.Underline: return 'underline'; + case TextEditorCursorStyle.LineThin: return 'line-thin'; + case TextEditorCursorStyle.BlockOutline: return 'block-outline'; + case TextEditorCursorStyle.UnderlineThin: return 'underline-thin'; } } -function _cursorStyleFromString(cursorStyle: string | undefined, defaultValue: TextEditorCursorStyle): TextEditorCursorStyle { - if (typeof cursorStyle !== 'string') { - return defaultValue; +function _cursorStyleFromString(cursorStyle: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin'): TextEditorCursorStyle { + switch (cursorStyle) { + case 'line': return TextEditorCursorStyle.Line; + case 'block': return TextEditorCursorStyle.Block; + case 'underline': return TextEditorCursorStyle.Underline; + case 'line-thin': return TextEditorCursorStyle.LineThin; + case 'block-outline': return TextEditorCursorStyle.BlockOutline; + case 'underline-thin': return TextEditorCursorStyle.UnderlineThin; } - if (cursorStyle === 'line') { - return TextEditorCursorStyle.Line; - } else if (cursorStyle === 'block') { - return TextEditorCursorStyle.Block; - } else if (cursorStyle === 'underline') { - return TextEditorCursorStyle.Underline; - } else if (cursorStyle === 'line-thin') { - return TextEditorCursorStyle.LineThin; - } else if (cursorStyle === 'block-outline') { - return TextEditorCursorStyle.BlockOutline; - } else if (cursorStyle === 'underline-thin') { - return TextEditorCursorStyle.UnderlineThin; - } - return TextEditorCursorStyle.Line; } -export interface InternalEditorScrollbarOptions { - readonly arrowSize: number; - readonly vertical: ScrollbarVisibility; - readonly horizontal: ScrollbarVisibility; - readonly useShadows: boolean; - readonly verticalHasArrows: boolean; - readonly horizontalHasArrows: boolean; - readonly handleMouseWheel: boolean; - readonly horizontalScrollbarSize: number; - readonly horizontalSliderSize: number; - readonly verticalScrollbarSize: number; - readonly verticalSliderSize: number; - readonly mouseWheelScrollSensitivity: number; - readonly fastScrollSensitivity: number; -} +//#endregion -export interface InternalEditorMinimapOptions { - readonly enabled: boolean; - readonly side: 'right' | 'left'; - readonly showSlider: 'always' | 'mouseover'; - readonly renderCharacters: boolean; - readonly maxColumn: number; -} +//#region editorClassName -export interface InternalEditorFindOptions { - readonly seedSearchStringFromSelection: boolean; - readonly autoFindInSelection: boolean; - readonly addExtraSpaceOnTop: boolean; - /** - * @internal - */ - readonly globalFindClipboard: boolean; -} +class EditorClassName extends ComputedEditorOption { -export interface InternalEditorHoverOptions { - readonly enabled: boolean; - readonly delay: number; - readonly sticky: boolean; -} - -export interface InternalGoToLocationOptions { - readonly multiple: 'peek' | 'gotoAndPeek' | 'goto'; -} - -export interface InternalSuggestOptions { - readonly filterGraceful: boolean; - readonly snippets: 'top' | 'bottom' | 'inline' | 'none'; - readonly snippetsPreventQuickSuggestions: boolean; - readonly localityBonus: boolean; - readonly shareSuggestSelections: boolean; - readonly showIcons: boolean; - readonly maxVisibleSuggestions: number; - readonly filteredTypes: Record; -} - -export interface InternalParameterHintOptions { - readonly enabled: boolean; - readonly cycle: boolean; -} - -export interface EditorWrappingInfo { - readonly inDiffEditor: boolean; - readonly isDominatedByLongLines: boolean; - readonly isWordWrapMinified: boolean; - readonly isViewportWrapping: boolean; - readonly wrappingColumn: number; - readonly wrappingIndent: WrappingIndent; - readonly wordWrapBreakBeforeCharacters: string; - readonly wordWrapBreakAfterCharacters: string; - readonly wordWrapBreakObtrusiveCharacters: string; -} - -export const enum RenderLineNumbersType { - Off = 0, - On = 1, - Relative = 2, - Interval = 3, - Custom = 4 -} - -export interface InternalEditorViewOptions { - readonly extraEditorClassName: string; - readonly disableMonospaceOptimizations: boolean; - readonly rulers: number[]; - readonly ariaLabel: string; - readonly renderLineNumbers: RenderLineNumbersType; - readonly renderCustomLineNumbers: ((lineNumber: number) => string) | null; - readonly cursorSurroundingLines: number; - readonly renderFinalNewline: boolean; - readonly selectOnLineNumbers: boolean; - readonly glyphMargin: boolean; - readonly revealHorizontalRightPadding: number; - readonly roundedSelection: boolean; - readonly overviewRulerLanes: number; - readonly overviewRulerBorder: boolean; - readonly cursorBlinking: TextEditorCursorBlinkingStyle; - readonly mouseWheelZoom: boolean; - readonly cursorSmoothCaretAnimation: boolean; - readonly cursorStyle: TextEditorCursorStyle; - readonly cursorWidth: number; - readonly hideCursorInOverviewRuler: boolean; - readonly scrollBeyondLastLine: boolean; - readonly scrollBeyondLastColumn: number; - readonly smoothScrolling: boolean; - readonly stopRenderingLineAfter: number; - readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all'; - readonly renderControlCharacters: boolean; - readonly fontLigatures: boolean; - readonly renderIndentGuides: boolean; - readonly highlightActiveIndentGuide: boolean; - readonly renderLineHighlight: 'none' | 'gutter' | 'line' | 'all'; - readonly scrollbar: InternalEditorScrollbarOptions; - readonly minimap: InternalEditorMinimapOptions; - readonly fixedOverflowWidgets: boolean; -} - -export interface EditorContribOptions { - readonly selectionClipboard: boolean; - readonly hover: InternalEditorHoverOptions; - readonly links: boolean; - readonly contextmenu: boolean; - readonly quickSuggestions: boolean | { other: boolean, comments: boolean, strings: boolean }; - readonly quickSuggestionsDelay: number; - readonly parameterHints: InternalParameterHintOptions; - readonly formatOnType: boolean; - readonly formatOnPaste: boolean; - readonly suggestOnTriggerCharacters: boolean; - readonly acceptSuggestionOnEnter: 'on' | 'smart' | 'off'; - readonly acceptSuggestionOnCommitCharacter: boolean; - readonly wordBasedSuggestions: boolean; - readonly suggestSelection: 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix'; - readonly suggestFontSize: number; - readonly suggestLineHeight: number; - readonly tabCompletion: 'on' | 'off' | 'onlySnippets'; - readonly suggest: InternalSuggestOptions; - readonly gotoLocation: InternalGoToLocationOptions; - readonly selectionHighlight: boolean; - readonly occurrencesHighlight: boolean; - readonly codeLens: boolean; - readonly folding: boolean; - readonly foldingStrategy: 'auto' | 'indentation'; - readonly showFoldingControls: 'always' | 'mouseover'; - readonly matchBrackets: boolean; - readonly find: InternalEditorFindOptions; - readonly colorDecorators: boolean; - readonly lightbulbEnabled: boolean; - readonly codeActionsOnSave: ICodeActionsOnSaveOptions; - readonly codeActionsOnSaveTimeout: number; -} - -/** - * Validated configuration options for the editor. - * This is a 1 to 1 validated/parsed version of IEditorOptions merged on top of the defaults. - * @internal - */ -export interface IValidatedEditorOptions { - readonly inDiffEditor: boolean; - readonly wordSeparators: string; - readonly lineNumbersMinChars: number; - readonly lineDecorationsWidth: number | string; - readonly readOnly: boolean; - readonly mouseStyle: 'text' | 'default' | 'copy'; - readonly disableLayerHinting: boolean; - readonly automaticLayout: boolean; - readonly wordWrap: 'off' | 'on' | 'wordWrapColumn' | 'bounded'; - readonly wordWrapColumn: number; - readonly wordWrapMinified: boolean; - readonly wrappingIndent: WrappingIndent; - readonly wordWrapBreakBeforeCharacters: string; - readonly wordWrapBreakAfterCharacters: string; - readonly wordWrapBreakObtrusiveCharacters: string; - readonly autoClosingBrackets: EditorAutoClosingStrategy; - readonly autoClosingQuotes: EditorAutoClosingStrategy; - readonly autoClosingOvertype: EditorAutoClosingOvertypeStrategy; - readonly autoSurround: EditorAutoSurroundStrategy; - readonly autoIndent: boolean; - readonly dragAndDrop: boolean; - readonly emptySelectionClipboard: boolean; - readonly copyWithSyntaxHighlighting: boolean; - readonly useTabStops: boolean; - readonly multiCursorModifier: 'altKey' | 'ctrlKey' | 'metaKey'; - readonly multiCursorMergeOverlapping: boolean; - readonly accessibilitySupport: 'auto' | 'off' | 'on'; - readonly showUnused: boolean; - - readonly viewInfo: InternalEditorViewOptions; - readonly contribInfo: EditorContribOptions; -} - -/** - * Internal configuration options (transformed or computed) for the editor. - */ -export class InternalEditorOptions { - readonly _internalEditorOptionsBrand: void; - - readonly canUseLayerHinting: boolean; - readonly pixelRatio: number; - readonly editorClassName: string; - readonly lineHeight: number; - readonly readOnly: boolean; - /** - * @internal - */ - readonly accessibilitySupport: AccessibilitySupport; - readonly multiCursorModifier: 'altKey' | 'ctrlKey' | 'metaKey'; - readonly multiCursorMergeOverlapping: boolean; - readonly showUnused: boolean; - - // ---- cursor options - readonly wordSeparators: string; - readonly autoClosingBrackets: EditorAutoClosingStrategy; - readonly autoClosingQuotes: EditorAutoClosingStrategy; - readonly autoClosingOvertype: EditorAutoClosingOvertypeStrategy; - readonly autoSurround: EditorAutoSurroundStrategy; - readonly autoIndent: boolean; - readonly useTabStops: boolean; - readonly tabFocusMode: boolean; - readonly dragAndDrop: boolean; - readonly emptySelectionClipboard: boolean; - readonly copyWithSyntaxHighlighting: boolean; - - // ---- grouped options - readonly layoutInfo: EditorLayoutInfo; - readonly fontInfo: FontInfo; - readonly viewInfo: InternalEditorViewOptions; - readonly wrappingInfo: EditorWrappingInfo; - readonly contribInfo: EditorContribOptions; - - /** - * @internal - */ - constructor(source: { - canUseLayerHinting: boolean; - pixelRatio: number; - editorClassName: string; - lineHeight: number; - readOnly: boolean; - accessibilitySupport: AccessibilitySupport; - multiCursorModifier: 'altKey' | 'ctrlKey' | 'metaKey'; - multiCursorMergeOverlapping: boolean; - wordSeparators: string; - autoClosingBrackets: EditorAutoClosingStrategy; - autoClosingQuotes: EditorAutoClosingStrategy; - autoClosingOvertype: EditorAutoClosingOvertypeStrategy; - autoSurround: EditorAutoSurroundStrategy; - autoIndent: boolean; - useTabStops: boolean; - tabFocusMode: boolean; - dragAndDrop: boolean; - emptySelectionClipboard: boolean; - copyWithSyntaxHighlighting: boolean; - layoutInfo: EditorLayoutInfo; - fontInfo: FontInfo; - viewInfo: InternalEditorViewOptions; - wrappingInfo: EditorWrappingInfo; - contribInfo: EditorContribOptions; - showUnused: boolean; - }) { - this.canUseLayerHinting = source.canUseLayerHinting; - this.pixelRatio = source.pixelRatio; - this.editorClassName = source.editorClassName; - this.lineHeight = source.lineHeight | 0; - this.readOnly = source.readOnly; - this.accessibilitySupport = source.accessibilitySupport; - this.multiCursorModifier = source.multiCursorModifier; - this.multiCursorMergeOverlapping = source.multiCursorMergeOverlapping; - this.wordSeparators = source.wordSeparators; - this.autoClosingBrackets = source.autoClosingBrackets; - this.autoClosingQuotes = source.autoClosingQuotes; - this.autoClosingOvertype = source.autoClosingOvertype; - this.autoSurround = source.autoSurround; - this.autoIndent = source.autoIndent; - this.useTabStops = source.useTabStops; - this.tabFocusMode = source.tabFocusMode; - this.dragAndDrop = source.dragAndDrop; - this.emptySelectionClipboard = source.emptySelectionClipboard; - this.copyWithSyntaxHighlighting = source.copyWithSyntaxHighlighting; - this.layoutInfo = source.layoutInfo; - this.fontInfo = source.fontInfo; - this.viewInfo = source.viewInfo; - this.wrappingInfo = source.wrappingInfo; - this.contribInfo = source.contribInfo; - this.showUnused = source.showUnused; + constructor() { + super(EditorOption.editorClassName, [EditorOption.mouseStyle, EditorOption.fontLigatures, EditorOption.extraEditorClassName]); } - /** - * @internal - */ - public equals(other: InternalEditorOptions): boolean { - return ( - this.canUseLayerHinting === other.canUseLayerHinting - && this.pixelRatio === other.pixelRatio - && this.editorClassName === other.editorClassName - && this.lineHeight === other.lineHeight - && this.readOnly === other.readOnly - && this.accessibilitySupport === other.accessibilitySupport - && this.multiCursorModifier === other.multiCursorModifier - && this.multiCursorMergeOverlapping === other.multiCursorMergeOverlapping - && this.wordSeparators === other.wordSeparators - && this.autoClosingBrackets === other.autoClosingBrackets - && this.autoClosingQuotes === other.autoClosingQuotes - && this.autoClosingOvertype === other.autoClosingOvertype - && this.autoSurround === other.autoSurround - && this.autoIndent === other.autoIndent - && this.useTabStops === other.useTabStops - && this.tabFocusMode === other.tabFocusMode - && this.dragAndDrop === other.dragAndDrop - && this.showUnused === other.showUnused - && this.emptySelectionClipboard === other.emptySelectionClipboard - && this.copyWithSyntaxHighlighting === other.copyWithSyntaxHighlighting - && InternalEditorOptions._equalsLayoutInfo(this.layoutInfo, other.layoutInfo) - && this.fontInfo.equals(other.fontInfo) - && InternalEditorOptions._equalsViewOptions(this.viewInfo, other.viewInfo) - && InternalEditorOptions._equalsWrappingInfo(this.wrappingInfo, other.wrappingInfo) - && InternalEditorOptions._equalsContribOptions(this.contribInfo, other.contribInfo) + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: string): string { + let className = 'monaco-editor'; + if (options.get(EditorOption.extraEditorClassName)) { + className += ' ' + options.get(EditorOption.extraEditorClassName); + } + if (env.extraEditorClassName) { + className += ' ' + env.extraEditorClassName; + } + if (options.get(EditorOption.fontLigatures)) { + className += ' enable-ligatures'; + } + if (options.get(EditorOption.mouseStyle) === 'default') { + className += ' mouse-default'; + } else if (options.get(EditorOption.mouseStyle) === 'copy') { + className += ' mouse-copy'; + } + return className; + } +} + +//#endregion + +//#region emptySelectionClipboard + +class EditorEmptySelectionClipboard extends EditorBooleanOption { + + constructor() { + super( + EditorOption.emptySelectionClipboard, 'emptySelectionClipboard', true, + { description: nls.localize('emptySelectionClipboard', "Controls whether copying without a selection copies the current line.") } ); } + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: boolean): boolean { + return value && env.emptySelectionClipboard; + } +} + +//#endregion + +//#region find + +/** + * Configuration options for editor find widget + */ +export interface IEditorFindOptions { + /** + * Controls if we seed search string in the Find Widget with editor selection. + */ + seedSearchStringFromSelection?: boolean; + /** + * Controls if Find in Selection flag is turned on when multiple lines of text are selected in the editor. + */ + autoFindInSelection?: boolean; + /* + * Controls whether the Find Widget should add extra lines on top of the editor. + */ + addExtraSpaceOnTop?: boolean; /** * @internal + * Controls if the Find Widget should read or modify the shared find clipboard on macOS */ - public createChangeEvent(newOpts: InternalEditorOptions): IConfigurationChangedEvent { + globalFindClipboard?: boolean; +} + +export type EditorFindOptions = Readonly>; + +class EditorFind extends BaseEditorOption { + + constructor() { + const defaults: EditorFindOptions = { + seedSearchStringFromSelection: true, + autoFindInSelection: false, + globalFindClipboard: false, + addExtraSpaceOnTop: true + }; + super( + EditorOption.find, 'find', defaults, + { + 'editor.find.seedSearchStringFromSelection': { + type: 'boolean', + default: defaults.seedSearchStringFromSelection, + description: nls.localize('find.seedSearchStringFromSelection', "Controls whether the search string in the Find Widget is seeded from the editor selection.") + }, + 'editor.find.autoFindInSelection': { + type: 'boolean', + default: defaults.autoFindInSelection, + description: nls.localize('find.autoFindInSelection', "Controls whether the find operation is carried out on selected text or the entire file in the editor.") + }, + 'editor.find.globalFindClipboard': { + type: 'boolean', + default: defaults.globalFindClipboard, + description: nls.localize('find.globalFindClipboard', "Controls whether the Find Widget should read or modify the shared find clipboard on macOS."), + included: platform.isMacintosh + }, + 'editor.find.addExtraSpaceOnTop': { + type: 'boolean', + default: defaults.addExtraSpaceOnTop, + description: nls.localize('find.addExtraSpaceOnTop', "Controls whether the Find Widget should add extra lines on top of the editor. When true, you can scroll beyond the first line when the Find Widget is visible.") + } + } + ); + } + + public validate(_input: any): EditorFindOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IEditorFindOptions; return { - canUseLayerHinting: (this.canUseLayerHinting !== newOpts.canUseLayerHinting), - pixelRatio: (this.pixelRatio !== newOpts.pixelRatio), - editorClassName: (this.editorClassName !== newOpts.editorClassName), - lineHeight: (this.lineHeight !== newOpts.lineHeight), - readOnly: (this.readOnly !== newOpts.readOnly), - accessibilitySupport: (this.accessibilitySupport !== newOpts.accessibilitySupport), - multiCursorModifier: (this.multiCursorModifier !== newOpts.multiCursorModifier), - multiCursorMergeOverlapping: (this.multiCursorMergeOverlapping !== newOpts.multiCursorMergeOverlapping), - wordSeparators: (this.wordSeparators !== newOpts.wordSeparators), - autoClosingBrackets: (this.autoClosingBrackets !== newOpts.autoClosingBrackets), - autoClosingQuotes: (this.autoClosingQuotes !== newOpts.autoClosingQuotes), - autoClosingOvertype: (this.autoClosingOvertype !== newOpts.autoClosingOvertype), - autoSurround: (this.autoSurround !== newOpts.autoSurround), - autoIndent: (this.autoIndent !== newOpts.autoIndent), - useTabStops: (this.useTabStops !== newOpts.useTabStops), - tabFocusMode: (this.tabFocusMode !== newOpts.tabFocusMode), - dragAndDrop: (this.dragAndDrop !== newOpts.dragAndDrop), - emptySelectionClipboard: (this.emptySelectionClipboard !== newOpts.emptySelectionClipboard), - copyWithSyntaxHighlighting: (this.copyWithSyntaxHighlighting !== newOpts.copyWithSyntaxHighlighting), - layoutInfo: (!InternalEditorOptions._equalsLayoutInfo(this.layoutInfo, newOpts.layoutInfo)), - fontInfo: (!this.fontInfo.equals(newOpts.fontInfo)), - viewInfo: (!InternalEditorOptions._equalsViewOptions(this.viewInfo, newOpts.viewInfo)), - wrappingInfo: (!InternalEditorOptions._equalsWrappingInfo(this.wrappingInfo, newOpts.wrappingInfo)), - contribInfo: (!InternalEditorOptions._equalsContribOptions(this.contribInfo, newOpts.contribInfo)) + seedSearchStringFromSelection: EditorBooleanOption.boolean(input.seedSearchStringFromSelection, this.defaultValue.seedSearchStringFromSelection), + autoFindInSelection: EditorBooleanOption.boolean(input.autoFindInSelection, this.defaultValue.autoFindInSelection), + globalFindClipboard: EditorBooleanOption.boolean(input.globalFindClipboard, this.defaultValue.globalFindClipboard), + addExtraSpaceOnTop: EditorBooleanOption.boolean(input.addExtraSpaceOnTop, this.defaultValue.addExtraSpaceOnTop) }; } +} - /** - * @internal - */ - private static _equalsLayoutInfo(a: EditorLayoutInfo, b: EditorLayoutInfo): boolean { - return ( - a.width === b.width - && a.height === b.height - && a.glyphMarginLeft === b.glyphMarginLeft - && a.glyphMarginWidth === b.glyphMarginWidth - && a.glyphMarginHeight === b.glyphMarginHeight - && a.lineNumbersLeft === b.lineNumbersLeft - && a.lineNumbersWidth === b.lineNumbersWidth - && a.lineNumbersHeight === b.lineNumbersHeight - && a.decorationsLeft === b.decorationsLeft - && a.decorationsWidth === b.decorationsWidth - && a.decorationsHeight === b.decorationsHeight - && a.contentLeft === b.contentLeft - && a.contentWidth === b.contentWidth - && a.contentHeight === b.contentHeight - && a.renderMinimap === b.renderMinimap - && a.minimapLeft === b.minimapLeft - && a.minimapWidth === b.minimapWidth - && a.viewportColumn === b.viewportColumn - && a.verticalScrollbarWidth === b.verticalScrollbarWidth - && a.horizontalScrollbarHeight === b.horizontalScrollbarHeight - && this._equalsOverviewRuler(a.overviewRuler, b.overviewRuler) - ); +//#endregion + +//#region fontInfo + +class EditorFontInfo extends ComputedEditorOption { + + constructor() { + super(EditorOption.fontInfo); } - /** - * @internal - */ - private static _equalsOverviewRuler(a: OverviewRulerPosition, b: OverviewRulerPosition): boolean { - return ( - a.width === b.width - && a.height === b.height - && a.top === b.top - && a.right === b.right - ); - } - - /** - * @internal - */ - private static _equalsViewOptions(a: InternalEditorViewOptions, b: InternalEditorViewOptions): boolean { - return ( - a.extraEditorClassName === b.extraEditorClassName - && a.disableMonospaceOptimizations === b.disableMonospaceOptimizations - && arrays.equals(a.rulers, b.rulers) - && a.ariaLabel === b.ariaLabel - && a.renderLineNumbers === b.renderLineNumbers - && a.renderCustomLineNumbers === b.renderCustomLineNumbers - && a.cursorSurroundingLines === b.cursorSurroundingLines - && a.renderFinalNewline === b.renderFinalNewline - && a.selectOnLineNumbers === b.selectOnLineNumbers - && a.glyphMargin === b.glyphMargin - && a.revealHorizontalRightPadding === b.revealHorizontalRightPadding - && a.roundedSelection === b.roundedSelection - && a.overviewRulerLanes === b.overviewRulerLanes - && a.overviewRulerBorder === b.overviewRulerBorder - && a.cursorBlinking === b.cursorBlinking - && a.mouseWheelZoom === b.mouseWheelZoom - && a.cursorSmoothCaretAnimation === b.cursorSmoothCaretAnimation - && a.cursorStyle === b.cursorStyle - && a.cursorWidth === b.cursorWidth - && a.hideCursorInOverviewRuler === b.hideCursorInOverviewRuler - && a.scrollBeyondLastLine === b.scrollBeyondLastLine - && a.scrollBeyondLastColumn === b.scrollBeyondLastColumn - && a.smoothScrolling === b.smoothScrolling - && a.stopRenderingLineAfter === b.stopRenderingLineAfter - && a.renderWhitespace === b.renderWhitespace - && a.renderControlCharacters === b.renderControlCharacters - && a.fontLigatures === b.fontLigatures - && a.renderIndentGuides === b.renderIndentGuides - && a.highlightActiveIndentGuide === b.highlightActiveIndentGuide - && a.renderLineHighlight === b.renderLineHighlight - && this._equalsScrollbarOptions(a.scrollbar, b.scrollbar) - && this._equalsMinimapOptions(a.minimap, b.minimap) - && a.fixedOverflowWidgets === b.fixedOverflowWidgets - ); - } - - /** - * @internal - */ - private static _equalsScrollbarOptions(a: InternalEditorScrollbarOptions, b: InternalEditorScrollbarOptions): boolean { - return ( - a.arrowSize === b.arrowSize - && a.vertical === b.vertical - && a.horizontal === b.horizontal - && a.useShadows === b.useShadows - && a.verticalHasArrows === b.verticalHasArrows - && a.horizontalHasArrows === b.horizontalHasArrows - && a.handleMouseWheel === b.handleMouseWheel - && a.horizontalScrollbarSize === b.horizontalScrollbarSize - && a.horizontalSliderSize === b.horizontalSliderSize - && a.verticalScrollbarSize === b.verticalScrollbarSize - && a.verticalSliderSize === b.verticalSliderSize - && a.mouseWheelScrollSensitivity === b.mouseWheelScrollSensitivity - && a.fastScrollSensitivity === b.fastScrollSensitivity - ); - } - - /** - * @internal - */ - private static _equalsMinimapOptions(a: InternalEditorMinimapOptions, b: InternalEditorMinimapOptions): boolean { - return ( - a.enabled === b.enabled - && a.side === b.side - && a.showSlider === b.showSlider - && a.renderCharacters === b.renderCharacters - && a.maxColumn === b.maxColumn - ); - } - - /** - * @internal - */ - private static _equalFindOptions(a: InternalEditorFindOptions, b: InternalEditorFindOptions): boolean { - return ( - a.seedSearchStringFromSelection === b.seedSearchStringFromSelection - && a.autoFindInSelection === b.autoFindInSelection - && a.globalFindClipboard === b.globalFindClipboard - && a.addExtraSpaceOnTop === b.addExtraSpaceOnTop - ); - } - - /** - * @internal - */ - private static _equalsParameterHintOptions(a: InternalParameterHintOptions, b: InternalParameterHintOptions): boolean { - return ( - a.enabled === b.enabled - && a.cycle === b.cycle - ); - } - - /** - * @internal - */ - private static _equalsHoverOptions(a: InternalEditorHoverOptions, b: InternalEditorHoverOptions): boolean { - return ( - a.enabled === b.enabled - && a.delay === b.delay - && a.sticky === b.sticky - ); - } - - /** - * @internal - */ - private static _equalsSuggestOptions(a: InternalSuggestOptions, b: InternalSuggestOptions): any { - if (a === b) { - return true; - } else if (!a || !b) { - return false; - } else { - return a.filterGraceful === b.filterGraceful - && a.snippets === b.snippets - && a.snippetsPreventQuickSuggestions === b.snippetsPreventQuickSuggestions - && a.localityBonus === b.localityBonus - && a.shareSuggestSelections === b.shareSuggestSelections - && a.showIcons === b.showIcons - && a.maxVisibleSuggestions === b.maxVisibleSuggestions - && objects.equals(a.filteredTypes, b.filteredTypes); - } - } - - private static _equalsGotoLocationOptions(a: InternalGoToLocationOptions | undefined, b: InternalGoToLocationOptions | undefined): boolean { - if (a === b) { - return true; - } else if (!a || !b) { - return false; - } else { - return a.multiple === b.multiple; - } - } - - /** - * @internal - */ - private static _equalsWrappingInfo(a: EditorWrappingInfo, b: EditorWrappingInfo): boolean { - return ( - a.inDiffEditor === b.inDiffEditor - && a.isDominatedByLongLines === b.isDominatedByLongLines - && a.isWordWrapMinified === b.isWordWrapMinified - && a.isViewportWrapping === b.isViewportWrapping - && a.wrappingColumn === b.wrappingColumn - && a.wrappingIndent === b.wrappingIndent - && a.wordWrapBreakBeforeCharacters === b.wordWrapBreakBeforeCharacters - && a.wordWrapBreakAfterCharacters === b.wordWrapBreakAfterCharacters - && a.wordWrapBreakObtrusiveCharacters === b.wordWrapBreakObtrusiveCharacters - ); - } - - /** - * @internal - */ - private static _equalsContribOptions(a: EditorContribOptions, b: EditorContribOptions): boolean { - return ( - a.selectionClipboard === b.selectionClipboard - && this._equalsHoverOptions(a.hover, b.hover) - && a.links === b.links - && a.contextmenu === b.contextmenu - && InternalEditorOptions._equalsQuickSuggestions(a.quickSuggestions, b.quickSuggestions) - && a.quickSuggestionsDelay === b.quickSuggestionsDelay - && this._equalsParameterHintOptions(a.parameterHints, b.parameterHints) - && a.formatOnType === b.formatOnType - && a.formatOnPaste === b.formatOnPaste - && a.suggestOnTriggerCharacters === b.suggestOnTriggerCharacters - && a.acceptSuggestionOnEnter === b.acceptSuggestionOnEnter - && a.acceptSuggestionOnCommitCharacter === b.acceptSuggestionOnCommitCharacter - && a.wordBasedSuggestions === b.wordBasedSuggestions - && a.suggestSelection === b.suggestSelection - && a.suggestFontSize === b.suggestFontSize - && a.suggestLineHeight === b.suggestLineHeight - && a.tabCompletion === b.tabCompletion - && this._equalsSuggestOptions(a.suggest, b.suggest) - && InternalEditorOptions._equalsGotoLocationOptions(a.gotoLocation, b.gotoLocation) - && a.selectionHighlight === b.selectionHighlight - && a.occurrencesHighlight === b.occurrencesHighlight - && a.codeLens === b.codeLens - && a.folding === b.folding - && a.foldingStrategy === b.foldingStrategy - && a.showFoldingControls === b.showFoldingControls - && a.matchBrackets === b.matchBrackets - && this._equalFindOptions(a.find, b.find) - && a.colorDecorators === b.colorDecorators - && objects.equals(a.codeActionsOnSave, b.codeActionsOnSave) - && a.codeActionsOnSaveTimeout === b.codeActionsOnSaveTimeout - && a.lightbulbEnabled === b.lightbulbEnabled - ); - } - - private static _equalsQuickSuggestions(a: boolean | { other: boolean, comments: boolean, strings: boolean }, b: boolean | { other: boolean, comments: boolean, strings: boolean }): boolean { - if (typeof a === 'boolean') { - if (typeof b !== 'boolean') { - return false; - } - return a === b; - } - if (typeof b === 'boolean') { - return false; - } - return ( - a.comments === b.comments - && a.other === b.other - && a.strings === b.strings - ); + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: FontInfo): FontInfo { + return env.fontInfo; } } +//#endregion + +//#region fontSize + +class EditorFontSize extends SimpleEditorOption { + + constructor() { + super( + EditorOption.fontSize, 'fontSize', EDITOR_FONT_DEFAULTS.fontSize, + { + type: 'number', + default: EDITOR_FONT_DEFAULTS.fontSize, + description: nls.localize('fontSize', "Controls the font size in pixels.") + } + ); + } + + public validate(input: any): number { + let r = EditorFloatOption.float(input, this.defaultValue); + if (r === 0) { + return EDITOR_FONT_DEFAULTS.fontSize; + } + return EditorFloatOption.clamp(r, 8, 100); + } + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: number): number { + // The final fontSize respects the editor zoom level. + // So take the result from env.fontInfo + return env.fontInfo.fontSize; + } +} + +//#endregion + +//#region gotoLocation + +/** + * Configuration options for go to location + */ +export interface IGotoLocationOptions { + /** + * Control how goto-command work when having multiple results. + */ + multiple?: 'peek' | 'gotoAndPeek' | 'goto'; +} + +export type GoToLocationOptions = Readonly>; + +class EditorGoToLocation extends BaseEditorOption { + + constructor() { + const defaults: GoToLocationOptions = { multiple: 'peek' }; + super( + EditorOption.gotoLocation, 'gotoLocation', defaults, + { + 'editor.gotoLocation.multiple': { + description: nls.localize('editor.gotoLocation.multiple', "Controls the behavior of 'Go To' commands, like Go To Definition, when multiple target locations exist."), + type: 'string', + enum: ['peek', 'gotoAndPeek', 'goto'], + default: defaults.multiple, + enumDescriptions: [ + nls.localize('editor.gotoLocation.multiple.peek', 'Show peek view of the results (default)'), + nls.localize('editor.gotoLocation.multiple.gotoAndPeek', 'Go to the primary result and show a peek view'), + nls.localize('editor.gotoLocation.multiple.goto', 'Go to the primary result and enable peek-less navigation to others') + ] + }, + } + ); + } + + public validate(_input: any): GoToLocationOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IGotoLocationOptions; + return { + multiple: EditorStringEnumOption.stringSet<'peek' | 'gotoAndPeek' | 'goto'>(input.multiple, this.defaultValue.multiple, ['peek', 'gotoAndPeek', 'goto']) + }; + } +} + +//#endregion + +//#region hover + +/** + * Configuration options for editor hover + */ +export interface IEditorHoverOptions { + /** + * Enable the hover. + * Defaults to true. + */ + enabled?: boolean; + /** + * Delay for showing the hover. + * Defaults to 300. + */ + delay?: number; + /** + * Is the hover sticky such that it can be clicked and its contents selected? + * Defaults to true. + */ + sticky?: boolean; +} + +export type EditorHoverOptions = Readonly>; + +class EditorHover extends BaseEditorOption { + + constructor() { + const defaults: EditorHoverOptions = { + enabled: true, + delay: 300, + sticky: true + }; + super( + EditorOption.hover, 'hover', defaults, + { + 'editor.hover.enabled': { + type: 'boolean', + default: defaults.enabled, + description: nls.localize('hover.enabled', "Controls whether the hover is shown.") + }, + 'editor.hover.delay': { + type: 'number', + default: defaults.delay, + description: nls.localize('hover.delay', "Controls the delay in milliseconds after which the hover is shown.") + }, + 'editor.hover.sticky': { + type: 'boolean', + default: defaults.sticky, + description: nls.localize('hover.sticky', "Controls whether the hover should remain visible when mouse is moved over it.") + }, + } + ); + } + + public validate(_input: any): EditorHoverOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IEditorHoverOptions; + return { + enabled: EditorBooleanOption.boolean(input.enabled, this.defaultValue.enabled), + delay: EditorIntOption.clampedInt(input.delay, this.defaultValue.delay, 0, 10000), + sticky: EditorBooleanOption.boolean(input.sticky, this.defaultValue.sticky) + }; + } +} + +//#endregion + +//#region layoutInfo + /** * A description for the overview ruler position. */ @@ -1540,6 +1354,14 @@ export interface OverviewRulerPosition { readonly right: number; } +export const enum RenderMinimap { + None = 0, + Small = 1, + Large = 2, + SmallBlocks = 3, + LargeBlocks = 4, +} + /** * The internal layout details of the editor. */ @@ -1641,851 +1463,79 @@ export interface EditorLayoutInfo { } /** - * An event describing that the configuration of the editor has changed. + * @internal */ -export interface IConfigurationChangedEvent { - readonly canUseLayerHinting: boolean; - readonly pixelRatio: boolean; - readonly editorClassName: boolean; - readonly lineHeight: boolean; - readonly readOnly: boolean; - readonly accessibilitySupport: boolean; - readonly multiCursorModifier: boolean; - readonly multiCursorMergeOverlapping: boolean; - readonly wordSeparators: boolean; - readonly autoClosingBrackets: boolean; - readonly autoClosingQuotes: boolean; - readonly autoClosingOvertype: boolean; - readonly autoSurround: boolean; - readonly autoIndent: boolean; - readonly useTabStops: boolean; - readonly tabFocusMode: boolean; - readonly dragAndDrop: boolean; - readonly emptySelectionClipboard: boolean; - readonly copyWithSyntaxHighlighting: boolean; - readonly layoutInfo: boolean; - readonly fontInfo: boolean; - readonly viewInfo: boolean; - readonly wrappingInfo: boolean; - readonly contribInfo: boolean; +export interface EditorLayoutInfoComputerEnv { + outerWidth: number; + outerHeight: number; + lineHeight: number; + lineNumbersDigitCount: number; + typicalHalfwidthCharacterWidth: number; + maxDigitWidth: number; + pixelRatio: number; } /** * @internal */ -export interface IEnvironmentalOptions { - readonly outerWidth: number; - readonly outerHeight: number; - readonly fontInfo: FontInfo; - readonly extraEditorClassName: string; - readonly isDominatedByLongLines: boolean; - readonly lineNumbersDigitCount: number; - readonly emptySelectionClipboard: boolean; - readonly pixelRatio: number; - readonly tabFocusMode: boolean; - readonly accessibilitySupport: AccessibilitySupport; -} +export class EditorLayoutInfoComputer extends ComputedEditorOption { -function _boolean(value: any, defaultValue: T): boolean | T { - if (typeof value === 'undefined') { - return defaultValue; - } - if (value === 'false') { - // treat the string 'false' as false - return false; - } - return Boolean(value); -} - -function _booleanMap(value: { [key: string]: boolean } | undefined, defaultValue: { [key: string]: boolean }): { [key: string]: boolean } { - if (!value) { - return defaultValue; + constructor() { + super( + EditorOption.layoutInfo, + [EditorOption.glyphMargin, EditorOption.lineDecorationsWidth, EditorOption.folding, EditorOption.minimap, EditorOption.scrollbar, EditorOption.lineNumbers] + ); } - const out = Object.create(null); - for (const k of Object.keys(value)) { - const v = value[k]; - if (typeof v === 'boolean') { - out[k] = v; - } - } - return out; -} - -function _string(value: any, defaultValue: string): string { - if (typeof value !== 'string') { - return defaultValue; - } - return value; -} - -function _stringSet(value: T | undefined, defaultValue: T, allowedValues: T[]): T { - if (typeof value !== 'string') { - return defaultValue; - } - if (allowedValues.indexOf(value) === -1) { - return defaultValue; - } - return value; -} - -function _clampedInt(value: any, defaultValue: number, minimum: number, maximum: number): number { - let r: number; - if (typeof value === 'undefined') { - r = defaultValue; - } else { - r = parseInt(value, 10); - if (isNaN(r)) { - r = defaultValue; - } - } - r = Math.max(minimum, r); - r = Math.min(maximum, r); - return r | 0; -} - -function _float(value: any, defaultValue: number): number { - let r = parseFloat(value); - if (isNaN(r)) { - r = defaultValue; - } - return r; -} - -function _wrappingIndentFromString(wrappingIndent: string | undefined, defaultValue: WrappingIndent): WrappingIndent { - if (typeof wrappingIndent !== 'string') { - return defaultValue; - } - if (wrappingIndent === 'same') { - return WrappingIndent.Same; - } else if (wrappingIndent === 'indent') { - return WrappingIndent.Indent; - } else if (wrappingIndent === 'deepIndent') { - return WrappingIndent.DeepIndent; - } else { - return WrappingIndent.None; - } -} - -function _cursorBlinkingStyleFromString(cursorBlinkingStyle: string | undefined, defaultValue: TextEditorCursorBlinkingStyle): TextEditorCursorBlinkingStyle { - if (typeof cursorBlinkingStyle !== 'string') { - return defaultValue; - } - switch (cursorBlinkingStyle) { - case 'blink': - return TextEditorCursorBlinkingStyle.Blink; - case 'smooth': - return TextEditorCursorBlinkingStyle.Smooth; - case 'phase': - return TextEditorCursorBlinkingStyle.Phase; - case 'expand': - return TextEditorCursorBlinkingStyle.Expand; - case 'visible': // maintain compatibility - case 'solid': - return TextEditorCursorBlinkingStyle.Solid; - } - return TextEditorCursorBlinkingStyle.Blink; -} - -function _scrollbarVisibilityFromString(visibility: string | undefined, defaultValue: ScrollbarVisibility): ScrollbarVisibility { - if (typeof visibility !== 'string') { - return defaultValue; - } - switch (visibility) { - case 'hidden': - return ScrollbarVisibility.Hidden; - case 'visible': - return ScrollbarVisibility.Visible; - default: - return ScrollbarVisibility.Auto; - } -} - -/** - * @internal - */ -export class EditorOptionsValidator { - - /** - * Validate raw editor options. - * i.e. since they can be defined by the user, they might be invalid. - */ - public static validate(opts: IEditorOptions, defaults: IValidatedEditorOptions): IValidatedEditorOptions { - let wordWrap = opts.wordWrap; - { - // Compatibility with old true or false values - if (wordWrap === true) { - wordWrap = 'on'; - } else if (wordWrap === false) { - wordWrap = 'off'; - } - - wordWrap = _stringSet<'off' | 'on' | 'wordWrapColumn' | 'bounded'>(wordWrap, defaults.wordWrap, ['off', 'on', 'wordWrapColumn', 'bounded']); - } - - const viewInfo = this._sanitizeViewInfo(opts, defaults.viewInfo); - const contribInfo = this._sanitizeContribInfo(opts, defaults.contribInfo); - - let configuredMulticursorModifier: 'altKey' | 'metaKey' | 'ctrlKey' | undefined = undefined; - if (typeof opts.multiCursorModifier === 'string') { - if (opts.multiCursorModifier === 'ctrlCmd') { - configuredMulticursorModifier = platform.isMacintosh ? 'metaKey' : 'ctrlKey'; - } else { - configuredMulticursorModifier = 'altKey'; - } - } - const multiCursorModifier = _stringSet<'altKey' | 'metaKey' | 'ctrlKey'>(configuredMulticursorModifier, defaults.multiCursorModifier, ['altKey', 'metaKey', 'ctrlKey']); - - let autoClosingBrackets: EditorAutoClosingStrategy; - let autoClosingQuotes: EditorAutoClosingStrategy; - let autoSurround: EditorAutoSurroundStrategy; - if (typeof opts.autoClosingBrackets === 'boolean' && opts.autoClosingBrackets === false) { - // backwards compatibility: disable all on boolean false - autoClosingBrackets = 'never'; - autoClosingQuotes = 'never'; - autoSurround = 'never'; - } else { - autoClosingBrackets = _stringSet(opts.autoClosingBrackets, defaults.autoClosingBrackets, ['always', 'languageDefined', 'beforeWhitespace', 'never']); - autoClosingQuotes = _stringSet(opts.autoClosingQuotes, defaults.autoClosingQuotes, ['always', 'languageDefined', 'beforeWhitespace', 'never']); - autoSurround = _stringSet(opts.autoSurround, defaults.autoSurround, ['languageDefined', 'brackets', 'quotes', 'never']); - } - - return { - inDiffEditor: _boolean(opts.inDiffEditor, defaults.inDiffEditor), - wordSeparators: _string(opts.wordSeparators, defaults.wordSeparators), - lineNumbersMinChars: _clampedInt(opts.lineNumbersMinChars, defaults.lineNumbersMinChars, 1, 10), - lineDecorationsWidth: (typeof opts.lineDecorationsWidth === 'undefined' ? defaults.lineDecorationsWidth : opts.lineDecorationsWidth), - readOnly: _boolean(opts.readOnly, defaults.readOnly), - mouseStyle: _stringSet<'text' | 'default' | 'copy'>(opts.mouseStyle, defaults.mouseStyle, ['text', 'default', 'copy']), - disableLayerHinting: _boolean(opts.disableLayerHinting, defaults.disableLayerHinting), - automaticLayout: _boolean(opts.automaticLayout, defaults.automaticLayout), - wordWrap: wordWrap, - wordWrapColumn: _clampedInt(opts.wordWrapColumn, defaults.wordWrapColumn, 1, Constants.MAX_SAFE_SMALL_INTEGER), - wordWrapMinified: _boolean(opts.wordWrapMinified, defaults.wordWrapMinified), - wrappingIndent: _wrappingIndentFromString(opts.wrappingIndent, defaults.wrappingIndent), - wordWrapBreakBeforeCharacters: _string(opts.wordWrapBreakBeforeCharacters, defaults.wordWrapBreakBeforeCharacters), - wordWrapBreakAfterCharacters: _string(opts.wordWrapBreakAfterCharacters, defaults.wordWrapBreakAfterCharacters), - wordWrapBreakObtrusiveCharacters: _string(opts.wordWrapBreakObtrusiveCharacters, defaults.wordWrapBreakObtrusiveCharacters), - autoClosingBrackets, - autoClosingQuotes, - autoClosingOvertype: _stringSet(opts.autoClosingOvertype, defaults.autoClosingOvertype, ['always', 'auto', 'never']), - autoSurround, - autoIndent: _boolean(opts.autoIndent, defaults.autoIndent), - dragAndDrop: _boolean(opts.dragAndDrop, defaults.dragAndDrop), - emptySelectionClipboard: _boolean(opts.emptySelectionClipboard, defaults.emptySelectionClipboard), - copyWithSyntaxHighlighting: _boolean(opts.copyWithSyntaxHighlighting, defaults.copyWithSyntaxHighlighting), - useTabStops: _boolean(opts.useTabStops, defaults.useTabStops), - multiCursorModifier: multiCursorModifier, - multiCursorMergeOverlapping: _boolean(opts.multiCursorMergeOverlapping, defaults.multiCursorMergeOverlapping), - accessibilitySupport: _stringSet<'auto' | 'on' | 'off'>(opts.accessibilitySupport, defaults.accessibilitySupport, ['auto', 'on', 'off']), - showUnused: _boolean(opts.showUnused, defaults.showUnused), - viewInfo: viewInfo, - contribInfo: contribInfo, - }; - } - - private static _sanitizeScrollbarOpts(opts: IEditorScrollbarOptions | undefined, defaults: InternalEditorScrollbarOptions, mouseWheelScrollSensitivity: number, fastScrollSensitivity: number): InternalEditorScrollbarOptions { - if (typeof opts !== 'object') { - return defaults; - } - const horizontalScrollbarSize = _clampedInt(opts.horizontalScrollbarSize, defaults.horizontalScrollbarSize, 0, 1000); - const verticalScrollbarSize = _clampedInt(opts.verticalScrollbarSize, defaults.verticalScrollbarSize, 0, 1000); - return { - vertical: _scrollbarVisibilityFromString(opts.vertical, defaults.vertical), - horizontal: _scrollbarVisibilityFromString(opts.horizontal, defaults.horizontal), - - arrowSize: _clampedInt(opts.arrowSize, defaults.arrowSize, 0, 1000), - useShadows: _boolean(opts.useShadows, defaults.useShadows), - - verticalHasArrows: _boolean(opts.verticalHasArrows, defaults.verticalHasArrows), - horizontalHasArrows: _boolean(opts.horizontalHasArrows, defaults.horizontalHasArrows), - - horizontalScrollbarSize: horizontalScrollbarSize, - horizontalSliderSize: _clampedInt(opts.horizontalSliderSize, horizontalScrollbarSize, 0, 1000), - - verticalScrollbarSize: verticalScrollbarSize, - verticalSliderSize: _clampedInt(opts.verticalSliderSize, verticalScrollbarSize, 0, 1000), - - handleMouseWheel: _boolean(opts.handleMouseWheel, defaults.handleMouseWheel), - mouseWheelScrollSensitivity: mouseWheelScrollSensitivity, - fastScrollSensitivity: fastScrollSensitivity, - }; - } - - private static _sanitizeMinimapOpts(opts: IEditorMinimapOptions | undefined, defaults: InternalEditorMinimapOptions): InternalEditorMinimapOptions { - if (typeof opts !== 'object') { - return defaults; - } - return { - enabled: _boolean(opts.enabled, defaults.enabled), - side: _stringSet<'right' | 'left'>(opts.side, defaults.side, ['right', 'left']), - showSlider: _stringSet<'always' | 'mouseover'>(opts.showSlider, defaults.showSlider, ['always', 'mouseover']), - renderCharacters: _boolean(opts.renderCharacters, defaults.renderCharacters), - maxColumn: _clampedInt(opts.maxColumn, defaults.maxColumn, 1, 10000), - }; - } - - private static _sanitizeFindOpts(opts: IEditorFindOptions | undefined, defaults: InternalEditorFindOptions): InternalEditorFindOptions { - if (typeof opts !== 'object') { - return defaults; - } - - return { - seedSearchStringFromSelection: _boolean(opts.seedSearchStringFromSelection, defaults.seedSearchStringFromSelection), - autoFindInSelection: _boolean(opts.autoFindInSelection, defaults.autoFindInSelection), - globalFindClipboard: _boolean(opts.globalFindClipboard, defaults.globalFindClipboard), - addExtraSpaceOnTop: _boolean(opts.addExtraSpaceOnTop, defaults.addExtraSpaceOnTop) - }; - } - - private static _sanitizeParameterHintOpts(opts: IEditorParameterHintOptions | undefined, defaults: InternalParameterHintOptions): InternalParameterHintOptions { - if (typeof opts !== 'object') { - return defaults; - } - - return { - enabled: _boolean(opts.enabled, defaults.enabled), - cycle: _boolean(opts.cycle, defaults.cycle) - }; - } - - private static _sanitizeHoverOpts(_opts: boolean | IEditorHoverOptions | undefined, defaults: InternalEditorHoverOptions): InternalEditorHoverOptions { - let opts: IEditorHoverOptions; - if (typeof _opts === 'boolean') { - opts = { - enabled: _opts - }; - } else if (typeof _opts === 'object') { - opts = _opts; - } else { - return defaults; - } - - return { - enabled: _boolean(opts.enabled, defaults.enabled), - delay: _clampedInt(opts.delay, defaults.delay, 0, 10000), - sticky: _boolean(opts.sticky, defaults.sticky) - }; - } - - private static _sanitizeSuggestOpts(opts: IEditorOptions, defaults: InternalSuggestOptions): InternalSuggestOptions { - const suggestOpts = opts.suggest || {}; - return { - filterGraceful: _boolean(suggestOpts.filterGraceful, defaults.filterGraceful), - snippets: _stringSet<'top' | 'bottom' | 'inline' | 'none'>(opts.snippetSuggestions, defaults.snippets, ['top', 'bottom', 'inline', 'none']), - snippetsPreventQuickSuggestions: _boolean(suggestOpts.snippetsPreventQuickSuggestions, defaults.filterGraceful), - localityBonus: _boolean(suggestOpts.localityBonus, defaults.localityBonus), - shareSuggestSelections: _boolean(suggestOpts.shareSuggestSelections, defaults.shareSuggestSelections), - showIcons: _boolean(suggestOpts.showIcons, defaults.showIcons), - maxVisibleSuggestions: _clampedInt(suggestOpts.maxVisibleSuggestions, defaults.maxVisibleSuggestions, 1, 15), - filteredTypes: isObject(suggestOpts.filteredTypes) ? suggestOpts.filteredTypes : Object.create(null) - }; - } - - private static _sanitizeGotoLocationOpts(opts: IEditorOptions, defaults: InternalGoToLocationOptions): InternalGoToLocationOptions { - const gotoOpts = opts.gotoLocation || {}; - return { - multiple: _stringSet<'peek' | 'gotoAndPeek' | 'goto'>(gotoOpts.multiple, defaults.multiple, ['peek', 'gotoAndPeek', 'goto']) - }; - } - - private static _sanitizeTabCompletionOpts(opts: boolean | 'on' | 'off' | 'onlySnippets' | undefined, defaults: 'on' | 'off' | 'onlySnippets'): 'on' | 'off' | 'onlySnippets' { - if (opts === false) { - return 'off'; - } else if (opts === true) { - return 'onlySnippets'; - } else { - return _stringSet<'on' | 'off' | 'onlySnippets'>(opts, defaults, ['on', 'off', 'onlySnippets']); - } - } - - private static _sanitizeViewInfo(opts: IEditorOptions, defaults: InternalEditorViewOptions): InternalEditorViewOptions { - - let rulers: number[] = []; - if (Array.isArray(opts.rulers)) { - for (let i = 0, len = opts.rulers.length; i < len; i++) { - rulers.push(_clampedInt(opts.rulers[i], 0, 0, 10000)); - } - rulers.sort(); - } - - let renderLineNumbers: RenderLineNumbersType = defaults.renderLineNumbers; - let renderCustomLineNumbers: ((lineNumber: number) => string) | null = defaults.renderCustomLineNumbers; - - if (typeof opts.lineNumbers !== 'undefined') { - let lineNumbers = opts.lineNumbers; - - // Compatibility with old true or false values - if (lineNumbers === true) { - lineNumbers = 'on'; - } else if (lineNumbers === false) { - lineNumbers = 'off'; - } - - if (typeof lineNumbers === 'function') { - renderLineNumbers = RenderLineNumbersType.Custom; - renderCustomLineNumbers = lineNumbers; - } else if (lineNumbers === 'interval') { - renderLineNumbers = RenderLineNumbersType.Interval; - } else if (lineNumbers === 'relative') { - renderLineNumbers = RenderLineNumbersType.Relative; - } else if (lineNumbers === 'on') { - renderLineNumbers = RenderLineNumbersType.On; - } else { - renderLineNumbers = RenderLineNumbersType.Off; - } - } - - const fontLigatures = _boolean(opts.fontLigatures, defaults.fontLigatures); - const disableMonospaceOptimizations = _boolean(opts.disableMonospaceOptimizations, defaults.disableMonospaceOptimizations) || fontLigatures; - - let renderWhitespace = opts.renderWhitespace; - { - // Compatibility with old true or false values - if (renderWhitespace === true) { - renderWhitespace = 'boundary'; - } else if (renderWhitespace === false) { - renderWhitespace = 'none'; - } - renderWhitespace = _stringSet<'none' | 'boundary' | 'selection' | 'all'>(renderWhitespace, defaults.renderWhitespace, ['none', 'boundary', 'selection', 'all']); - } - - let renderLineHighlight = opts.renderLineHighlight; - { - // Compatibility with old true or false values - if (renderLineHighlight === true) { - renderLineHighlight = 'line'; - } else if (renderLineHighlight === false) { - renderLineHighlight = 'none'; - } - renderLineHighlight = _stringSet<'none' | 'gutter' | 'line' | 'all'>(renderLineHighlight, defaults.renderLineHighlight, ['none', 'gutter', 'line', 'all']); - } - - let mouseWheelScrollSensitivity = _float(opts.mouseWheelScrollSensitivity, defaults.scrollbar.mouseWheelScrollSensitivity); - if (mouseWheelScrollSensitivity === 0) { - // Disallow 0, as it would prevent/block scrolling - mouseWheelScrollSensitivity = 1; - } - - let fastScrollSensitivity = _float(opts.fastScrollSensitivity, defaults.scrollbar.fastScrollSensitivity); - if (fastScrollSensitivity <= 0) { - fastScrollSensitivity = defaults.scrollbar.fastScrollSensitivity; - } - const scrollbar = this._sanitizeScrollbarOpts(opts.scrollbar, defaults.scrollbar, mouseWheelScrollSensitivity, fastScrollSensitivity); - const minimap = this._sanitizeMinimapOpts(opts.minimap, defaults.minimap); - - return { - extraEditorClassName: _string(opts.extraEditorClassName, defaults.extraEditorClassName), - disableMonospaceOptimizations: disableMonospaceOptimizations, - rulers: rulers, - ariaLabel: _string(opts.ariaLabel, defaults.ariaLabel), - cursorSurroundingLines: _clampedInt(opts.cursorSurroundingLines, defaults.cursorWidth, 0, Number.MAX_VALUE), - renderLineNumbers: renderLineNumbers, - renderCustomLineNumbers: renderCustomLineNumbers, - renderFinalNewline: _boolean(opts.renderFinalNewline, defaults.renderFinalNewline), - selectOnLineNumbers: _boolean(opts.selectOnLineNumbers, defaults.selectOnLineNumbers), - glyphMargin: _boolean(opts.glyphMargin, defaults.glyphMargin), - revealHorizontalRightPadding: _clampedInt(opts.revealHorizontalRightPadding, defaults.revealHorizontalRightPadding, 0, 1000), - roundedSelection: _boolean(opts.roundedSelection, defaults.roundedSelection), - overviewRulerLanes: _clampedInt(opts.overviewRulerLanes, defaults.overviewRulerLanes, 0, 3), - overviewRulerBorder: _boolean(opts.overviewRulerBorder, defaults.overviewRulerBorder), - cursorBlinking: _cursorBlinkingStyleFromString(opts.cursorBlinking, defaults.cursorBlinking), - mouseWheelZoom: _boolean(opts.mouseWheelZoom, defaults.mouseWheelZoom), - cursorSmoothCaretAnimation: _boolean(opts.cursorSmoothCaretAnimation, defaults.cursorSmoothCaretAnimation), - cursorStyle: _cursorStyleFromString(opts.cursorStyle, defaults.cursorStyle), - cursorWidth: _clampedInt(opts.cursorWidth, defaults.cursorWidth, 0, Number.MAX_VALUE), - hideCursorInOverviewRuler: _boolean(opts.hideCursorInOverviewRuler, defaults.hideCursorInOverviewRuler), - scrollBeyondLastLine: _boolean(opts.scrollBeyondLastLine, defaults.scrollBeyondLastLine), - scrollBeyondLastColumn: _clampedInt(opts.scrollBeyondLastColumn, defaults.scrollBeyondLastColumn, 0, Constants.MAX_SAFE_SMALL_INTEGER), - smoothScrolling: _boolean(opts.smoothScrolling, defaults.smoothScrolling), - stopRenderingLineAfter: _clampedInt(opts.stopRenderingLineAfter, defaults.stopRenderingLineAfter, -1, Constants.MAX_SAFE_SMALL_INTEGER), - renderWhitespace: renderWhitespace, - renderControlCharacters: _boolean(opts.renderControlCharacters, defaults.renderControlCharacters), - fontLigatures: fontLigatures, - renderIndentGuides: _boolean(opts.renderIndentGuides, defaults.renderIndentGuides), - highlightActiveIndentGuide: _boolean(opts.highlightActiveIndentGuide, defaults.highlightActiveIndentGuide), - renderLineHighlight: renderLineHighlight, - scrollbar: scrollbar, - minimap: minimap, - fixedOverflowWidgets: _boolean(opts.fixedOverflowWidgets, defaults.fixedOverflowWidgets), - }; - } - - private static _sanitizeContribInfo(opts: IEditorOptions, defaults: EditorContribOptions): EditorContribOptions { - let quickSuggestions: boolean | { other: boolean, comments: boolean, strings: boolean }; - if (typeof opts.quickSuggestions === 'object') { - quickSuggestions = { other: true, ...opts.quickSuggestions }; - } else { - quickSuggestions = _boolean(opts.quickSuggestions, defaults.quickSuggestions); - } - // Compatibility support for acceptSuggestionOnEnter - if (typeof opts.acceptSuggestionOnEnter === 'boolean') { - opts.acceptSuggestionOnEnter = opts.acceptSuggestionOnEnter ? 'on' : 'off'; - } - const find = this._sanitizeFindOpts(opts.find, defaults.find); - return { - selectionClipboard: _boolean(opts.selectionClipboard, defaults.selectionClipboard), - hover: this._sanitizeHoverOpts(opts.hover, defaults.hover), - links: _boolean(opts.links, defaults.links), - contextmenu: _boolean(opts.contextmenu, defaults.contextmenu), - quickSuggestions: quickSuggestions, - quickSuggestionsDelay: _clampedInt(opts.quickSuggestionsDelay, defaults.quickSuggestionsDelay, Constants.MIN_SAFE_SMALL_INTEGER, Constants.MAX_SAFE_SMALL_INTEGER), - parameterHints: this._sanitizeParameterHintOpts(opts.parameterHints, defaults.parameterHints), - formatOnType: _boolean(opts.formatOnType, defaults.formatOnType), - formatOnPaste: _boolean(opts.formatOnPaste, defaults.formatOnPaste), - suggestOnTriggerCharacters: _boolean(opts.suggestOnTriggerCharacters, defaults.suggestOnTriggerCharacters), - acceptSuggestionOnEnter: _stringSet<'on' | 'smart' | 'off'>(opts.acceptSuggestionOnEnter, defaults.acceptSuggestionOnEnter, ['on', 'smart', 'off']), - acceptSuggestionOnCommitCharacter: _boolean(opts.acceptSuggestionOnCommitCharacter, defaults.acceptSuggestionOnCommitCharacter), - wordBasedSuggestions: _boolean(opts.wordBasedSuggestions, defaults.wordBasedSuggestions), - suggestSelection: _stringSet<'first' | 'recentlyUsed' | 'recentlyUsedByPrefix'>(opts.suggestSelection, defaults.suggestSelection, ['first', 'recentlyUsed', 'recentlyUsedByPrefix']), - suggestFontSize: _clampedInt(opts.suggestFontSize, defaults.suggestFontSize, 0, 1000), - suggestLineHeight: _clampedInt(opts.suggestLineHeight, defaults.suggestLineHeight, 0, 1000), - tabCompletion: this._sanitizeTabCompletionOpts(opts.tabCompletion, defaults.tabCompletion), - suggest: this._sanitizeSuggestOpts(opts, defaults.suggest), - gotoLocation: this._sanitizeGotoLocationOpts(opts, defaults.gotoLocation), - selectionHighlight: _boolean(opts.selectionHighlight, defaults.selectionHighlight), - occurrencesHighlight: _boolean(opts.occurrencesHighlight, defaults.occurrencesHighlight), - codeLens: _boolean(opts.codeLens, defaults.codeLens), - folding: _boolean(opts.folding, defaults.folding), - foldingStrategy: _stringSet<'auto' | 'indentation'>(opts.foldingStrategy, defaults.foldingStrategy, ['auto', 'indentation']), - showFoldingControls: _stringSet<'always' | 'mouseover'>(opts.showFoldingControls, defaults.showFoldingControls, ['always', 'mouseover']), - matchBrackets: _boolean(opts.matchBrackets, defaults.matchBrackets), - find: find, - colorDecorators: _boolean(opts.colorDecorators, defaults.colorDecorators), - lightbulbEnabled: _boolean(opts.lightbulb ? opts.lightbulb.enabled : false, defaults.lightbulbEnabled), - codeActionsOnSave: _booleanMap(opts.codeActionsOnSave, {}), - codeActionsOnSaveTimeout: _clampedInt(opts.codeActionsOnSaveTimeout, defaults.codeActionsOnSaveTimeout, 1, 10000) - }; - } -} - -/** - * @internal - */ -export class InternalEditorOptionsFactory { - - private static _tweakValidatedOptions(opts: IValidatedEditorOptions, accessibilitySupport: AccessibilitySupport): IValidatedEditorOptions { - const accessibilityIsOff = (accessibilitySupport === AccessibilitySupport.Disabled); - return { - inDiffEditor: opts.inDiffEditor, - wordSeparators: opts.wordSeparators, - lineNumbersMinChars: opts.lineNumbersMinChars, - lineDecorationsWidth: opts.lineDecorationsWidth, - readOnly: opts.readOnly, - mouseStyle: opts.mouseStyle, - disableLayerHinting: opts.disableLayerHinting, - automaticLayout: opts.automaticLayout, - wordWrap: opts.wordWrap, - wordWrapColumn: opts.wordWrapColumn, - wordWrapMinified: opts.wordWrapMinified, - wrappingIndent: opts.wrappingIndent, - wordWrapBreakBeforeCharacters: opts.wordWrapBreakBeforeCharacters, - wordWrapBreakAfterCharacters: opts.wordWrapBreakAfterCharacters, - wordWrapBreakObtrusiveCharacters: opts.wordWrapBreakObtrusiveCharacters, - autoClosingBrackets: opts.autoClosingBrackets, - autoClosingQuotes: opts.autoClosingQuotes, - autoClosingOvertype: opts.autoClosingOvertype, - autoSurround: opts.autoSurround, - autoIndent: opts.autoIndent, - dragAndDrop: opts.dragAndDrop, - emptySelectionClipboard: opts.emptySelectionClipboard, - copyWithSyntaxHighlighting: opts.copyWithSyntaxHighlighting, - useTabStops: opts.useTabStops, - multiCursorModifier: opts.multiCursorModifier, - multiCursorMergeOverlapping: opts.multiCursorMergeOverlapping, - accessibilitySupport: opts.accessibilitySupport, - showUnused: opts.showUnused, - - viewInfo: { - extraEditorClassName: opts.viewInfo.extraEditorClassName, - disableMonospaceOptimizations: opts.viewInfo.disableMonospaceOptimizations, - rulers: opts.viewInfo.rulers, - ariaLabel: (accessibilityIsOff ? nls.localize('accessibilityOffAriaLabel', "The editor is not accessible at this time. Press Alt+F1 for options.") : opts.viewInfo.ariaLabel), - renderLineNumbers: opts.viewInfo.renderLineNumbers, - renderCustomLineNumbers: opts.viewInfo.renderCustomLineNumbers, - cursorSurroundingLines: opts.viewInfo.cursorSurroundingLines, - renderFinalNewline: opts.viewInfo.renderFinalNewline, - selectOnLineNumbers: opts.viewInfo.selectOnLineNumbers, - glyphMargin: opts.viewInfo.glyphMargin, - revealHorizontalRightPadding: opts.viewInfo.revealHorizontalRightPadding, - roundedSelection: opts.viewInfo.roundedSelection, - overviewRulerLanes: opts.viewInfo.overviewRulerLanes, - overviewRulerBorder: opts.viewInfo.overviewRulerBorder, - cursorBlinking: opts.viewInfo.cursorBlinking, - mouseWheelZoom: opts.viewInfo.mouseWheelZoom, - cursorSmoothCaretAnimation: opts.viewInfo.cursorSmoothCaretAnimation, - cursorStyle: opts.viewInfo.cursorStyle, - cursorWidth: opts.viewInfo.cursorWidth, - hideCursorInOverviewRuler: opts.viewInfo.hideCursorInOverviewRuler, - scrollBeyondLastLine: opts.viewInfo.scrollBeyondLastLine, - scrollBeyondLastColumn: opts.viewInfo.scrollBeyondLastColumn, - smoothScrolling: opts.viewInfo.smoothScrolling, - stopRenderingLineAfter: opts.viewInfo.stopRenderingLineAfter, - renderWhitespace: opts.viewInfo.renderWhitespace, - renderControlCharacters: opts.viewInfo.renderControlCharacters, - fontLigatures: opts.viewInfo.fontLigatures, - renderIndentGuides: opts.viewInfo.renderIndentGuides, - highlightActiveIndentGuide: opts.viewInfo.highlightActiveIndentGuide, - renderLineHighlight: opts.viewInfo.renderLineHighlight, - scrollbar: opts.viewInfo.scrollbar, - minimap: { - enabled: opts.viewInfo.minimap.enabled, - side: opts.viewInfo.minimap.side, - renderCharacters: opts.viewInfo.minimap.renderCharacters, - showSlider: opts.viewInfo.minimap.showSlider, - maxColumn: opts.viewInfo.minimap.maxColumn - }, - fixedOverflowWidgets: opts.viewInfo.fixedOverflowWidgets - }, - - contribInfo: { - selectionClipboard: opts.contribInfo.selectionClipboard, - hover: opts.contribInfo.hover, - links: opts.contribInfo.links, - contextmenu: opts.contribInfo.contextmenu, - quickSuggestions: opts.contribInfo.quickSuggestions, - quickSuggestionsDelay: opts.contribInfo.quickSuggestionsDelay, - parameterHints: opts.contribInfo.parameterHints, - formatOnType: opts.contribInfo.formatOnType, - formatOnPaste: opts.contribInfo.formatOnPaste, - suggestOnTriggerCharacters: opts.contribInfo.suggestOnTriggerCharacters, - acceptSuggestionOnEnter: opts.contribInfo.acceptSuggestionOnEnter, - acceptSuggestionOnCommitCharacter: opts.contribInfo.acceptSuggestionOnCommitCharacter, - wordBasedSuggestions: opts.contribInfo.wordBasedSuggestions, - suggestSelection: opts.contribInfo.suggestSelection, - suggestFontSize: opts.contribInfo.suggestFontSize, - suggestLineHeight: opts.contribInfo.suggestLineHeight, - tabCompletion: opts.contribInfo.tabCompletion, - suggest: opts.contribInfo.suggest, - gotoLocation: opts.contribInfo.gotoLocation, - selectionHighlight: opts.contribInfo.selectionHighlight, - occurrencesHighlight: opts.contribInfo.occurrencesHighlight, - codeLens: opts.contribInfo.codeLens, - folding: opts.contribInfo.folding, - foldingStrategy: opts.contribInfo.foldingStrategy, - showFoldingControls: opts.contribInfo.showFoldingControls, - matchBrackets: opts.contribInfo.matchBrackets, - find: opts.contribInfo.find, - colorDecorators: opts.contribInfo.colorDecorators, - lightbulbEnabled: opts.contribInfo.lightbulbEnabled, - codeActionsOnSave: opts.contribInfo.codeActionsOnSave, - codeActionsOnSaveTimeout: opts.contribInfo.codeActionsOnSaveTimeout - } - }; - } - - public static createInternalEditorOptions(env: IEnvironmentalOptions, _opts: IValidatedEditorOptions) { - - let accessibilitySupport: AccessibilitySupport; - if (_opts.accessibilitySupport === 'auto') { - // The editor reads the `accessibilitySupport` from the environment - accessibilitySupport = env.accessibilitySupport; - } else if (_opts.accessibilitySupport === 'on') { - accessibilitySupport = AccessibilitySupport.Enabled; - } else { - accessibilitySupport = AccessibilitySupport.Disabled; - } - - // Disable some non critical features to get as best performance as possible - // See https://github.com/Microsoft/vscode/issues/26730 - const opts = this._tweakValidatedOptions(_opts, accessibilitySupport); - - let lineDecorationsWidth: number; - if (typeof opts.lineDecorationsWidth === 'string' && /^\d+(\.\d+)?ch$/.test(opts.lineDecorationsWidth)) { - const multiple = parseFloat(opts.lineDecorationsWidth.substr(0, opts.lineDecorationsWidth.length - 2)); - lineDecorationsWidth = multiple * env.fontInfo.typicalHalfwidthCharacterWidth; - } else { - lineDecorationsWidth = _clampedInt(opts.lineDecorationsWidth, 0, 0, 1000); - } - if (opts.contribInfo.folding) { - lineDecorationsWidth += 16; - } - - const layoutInfo = EditorLayoutProvider.compute({ + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: EditorLayoutInfo): EditorLayoutInfo { + return EditorLayoutInfoComputer.computeLayout(options, { outerWidth: env.outerWidth, outerHeight: env.outerHeight, - showGlyphMargin: opts.viewInfo.glyphMargin, lineHeight: env.fontInfo.lineHeight, - showLineNumbers: (opts.viewInfo.renderLineNumbers !== RenderLineNumbersType.Off), - lineNumbersMinChars: opts.lineNumbersMinChars, lineNumbersDigitCount: env.lineNumbersDigitCount, - lineDecorationsWidth: lineDecorationsWidth, typicalHalfwidthCharacterWidth: env.fontInfo.typicalHalfwidthCharacterWidth, maxDigitWidth: env.fontInfo.maxDigitWidth, - verticalScrollbarWidth: opts.viewInfo.scrollbar.verticalScrollbarSize, - horizontalScrollbarHeight: opts.viewInfo.scrollbar.horizontalScrollbarSize, - scrollbarArrowSize: opts.viewInfo.scrollbar.arrowSize, - verticalScrollbarHasArrows: opts.viewInfo.scrollbar.verticalHasArrows, - minimap: opts.viewInfo.minimap.enabled, - minimapSide: opts.viewInfo.minimap.side, - minimapRenderCharacters: opts.viewInfo.minimap.renderCharacters, - minimapMaxColumn: opts.viewInfo.minimap.maxColumn, pixelRatio: env.pixelRatio }); - - let bareWrappingInfo: { isWordWrapMinified: boolean; isViewportWrapping: boolean; wrappingColumn: number; } | null = null; - { - const wordWrap = opts.wordWrap; - const wordWrapColumn = opts.wordWrapColumn; - const wordWrapMinified = opts.wordWrapMinified; - - if (accessibilitySupport === AccessibilitySupport.Enabled) { - // See https://github.com/Microsoft/vscode/issues/27766 - // Never enable wrapping when a screen reader is attached - // because arrow down etc. will not move the cursor in the way - // a screen reader expects. - bareWrappingInfo = { - isWordWrapMinified: false, - isViewportWrapping: false, - wrappingColumn: -1 - }; - } else if (wordWrapMinified && env.isDominatedByLongLines) { - // Force viewport width wrapping if model is dominated by long lines - bareWrappingInfo = { - isWordWrapMinified: true, - isViewportWrapping: true, - wrappingColumn: Math.max(1, layoutInfo.viewportColumn) - }; - } else if (wordWrap === 'on') { - bareWrappingInfo = { - isWordWrapMinified: false, - isViewportWrapping: true, - wrappingColumn: Math.max(1, layoutInfo.viewportColumn) - }; - } else if (wordWrap === 'bounded') { - bareWrappingInfo = { - isWordWrapMinified: false, - isViewportWrapping: true, - wrappingColumn: Math.min(Math.max(1, layoutInfo.viewportColumn), wordWrapColumn) - }; - } else if (wordWrap === 'wordWrapColumn') { - bareWrappingInfo = { - isWordWrapMinified: false, - isViewportWrapping: false, - wrappingColumn: wordWrapColumn - }; - } else { - bareWrappingInfo = { - isWordWrapMinified: false, - isViewportWrapping: false, - wrappingColumn: -1 - }; - } - } - - const wrappingInfo: EditorWrappingInfo = { - inDiffEditor: opts.inDiffEditor, - isDominatedByLongLines: env.isDominatedByLongLines, - isWordWrapMinified: bareWrappingInfo.isWordWrapMinified, - isViewportWrapping: bareWrappingInfo.isViewportWrapping, - wrappingColumn: bareWrappingInfo.wrappingColumn, - wrappingIndent: opts.wrappingIndent, - wordWrapBreakBeforeCharacters: opts.wordWrapBreakBeforeCharacters, - wordWrapBreakAfterCharacters: opts.wordWrapBreakAfterCharacters, - wordWrapBreakObtrusiveCharacters: opts.wordWrapBreakObtrusiveCharacters, - }; - - let className = 'monaco-editor'; - if (opts.viewInfo.extraEditorClassName) { - className += ' ' + opts.viewInfo.extraEditorClassName; - } - if (env.extraEditorClassName) { - className += ' ' + env.extraEditorClassName; - } - if (opts.viewInfo.fontLigatures) { - className += ' enable-ligatures'; - } - if (opts.mouseStyle === 'default') { - className += ' mouse-default'; - } else if (opts.mouseStyle === 'copy') { - className += ' mouse-copy'; - } - - return new InternalEditorOptions({ - canUseLayerHinting: opts.disableLayerHinting ? false : true, - pixelRatio: env.pixelRatio, - editorClassName: className, - lineHeight: env.fontInfo.lineHeight, - readOnly: opts.readOnly, - accessibilitySupport: accessibilitySupport, - multiCursorModifier: opts.multiCursorModifier, - multiCursorMergeOverlapping: opts.multiCursorMergeOverlapping, - wordSeparators: opts.wordSeparators, - autoClosingBrackets: opts.autoClosingBrackets, - autoClosingQuotes: opts.autoClosingQuotes, - autoClosingOvertype: opts.autoClosingOvertype, - autoSurround: opts.autoSurround, - autoIndent: opts.autoIndent, - useTabStops: opts.useTabStops, - tabFocusMode: opts.readOnly ? true : env.tabFocusMode, - dragAndDrop: opts.dragAndDrop, - emptySelectionClipboard: opts.emptySelectionClipboard && env.emptySelectionClipboard, - copyWithSyntaxHighlighting: opts.copyWithSyntaxHighlighting, - layoutInfo: layoutInfo, - fontInfo: env.fontInfo, - viewInfo: opts.viewInfo, - wrappingInfo: wrappingInfo, - contribInfo: opts.contribInfo, - showUnused: opts.showUnused, - }); } -} -/** - * @internal - */ -export interface IEditorLayoutProviderOpts { - readonly outerWidth: number; - readonly outerHeight: number; + public static computeLayout(options: IComputedEditorOptions, env: EditorLayoutInfoComputerEnv): EditorLayoutInfo { + const outerWidth = env.outerWidth | 0; + const outerHeight = env.outerHeight | 0; + const lineHeight = env.lineHeight | 0; + const lineNumbersDigitCount = env.lineNumbersDigitCount | 0; + const typicalHalfwidthCharacterWidth = env.typicalHalfwidthCharacterWidth; + const maxDigitWidth = env.maxDigitWidth; + const pixelRatio = env.pixelRatio; - readonly showGlyphMargin: boolean; - readonly lineHeight: number; + const showGlyphMargin = options.get(EditorOption.glyphMargin); + const showLineNumbers = (options.get(EditorOption.lineNumbers).renderType !== RenderLineNumbersType.Off); + const lineNumbersMinChars = options.get(EditorOption.lineNumbersMinChars) | 0; + const minimap = options.get(EditorOption.minimap); + const minimapEnabled = minimap.enabled; + const minimapSide = minimap.side; + const minimapRenderCharacters = minimap.renderCharacters; + const minimapMaxColumn = minimap.maxColumn | 0; - readonly showLineNumbers: boolean; - readonly lineNumbersMinChars: number; - readonly lineNumbersDigitCount: number; + const scrollbar = options.get(EditorOption.scrollbar); + const verticalScrollbarWidth = scrollbar.verticalScrollbarSize | 0; + const verticalScrollbarHasArrows = scrollbar.verticalHasArrows; + const scrollbarArrowSize = scrollbar.arrowSize | 0; + const horizontalScrollbarHeight = scrollbar.horizontalScrollbarSize | 0; - readonly lineDecorationsWidth: number; + const rawLineDecorationsWidth = options.get(EditorOption.lineDecorationsWidth); + const folding = options.get(EditorOption.folding); - readonly typicalHalfwidthCharacterWidth: number; - readonly maxDigitWidth: number; - - readonly verticalScrollbarWidth: number; - readonly verticalScrollbarHasArrows: boolean; - readonly scrollbarArrowSize: number; - readonly horizontalScrollbarHeight: number; - - readonly minimap: boolean; - readonly minimapSide: string; - readonly minimapRenderCharacters: boolean; - readonly minimapMaxColumn: number; - readonly pixelRatio: number; -} - -/** - * @internal - */ -export class EditorLayoutProvider { - public static compute(_opts: IEditorLayoutProviderOpts): EditorLayoutInfo { - const outerWidth = _opts.outerWidth | 0; - const outerHeight = _opts.outerHeight | 0; - const showGlyphMargin = _opts.showGlyphMargin; - const lineHeight = _opts.lineHeight | 0; - const showLineNumbers = _opts.showLineNumbers; - const lineNumbersMinChars = _opts.lineNumbersMinChars | 0; - const lineNumbersDigitCount = _opts.lineNumbersDigitCount | 0; - const lineDecorationsWidth = _opts.lineDecorationsWidth | 0; - const typicalHalfwidthCharacterWidth = _opts.typicalHalfwidthCharacterWidth; - const maxDigitWidth = _opts.maxDigitWidth; - const verticalScrollbarWidth = _opts.verticalScrollbarWidth | 0; - const verticalScrollbarHasArrows = _opts.verticalScrollbarHasArrows; - const scrollbarArrowSize = _opts.scrollbarArrowSize | 0; - const horizontalScrollbarHeight = _opts.horizontalScrollbarHeight | 0; - const minimap = _opts.minimap; - const minimapSide = _opts.minimapSide; - const minimapRenderCharacters = _opts.minimapRenderCharacters; - const minimapMaxColumn = _opts.minimapMaxColumn | 0; - const pixelRatio = _opts.pixelRatio; + let lineDecorationsWidth: number; + if (typeof rawLineDecorationsWidth === 'string' && /^\d+(\.\d+)?ch$/.test(rawLineDecorationsWidth)) { + const multiple = parseFloat(rawLineDecorationsWidth.substr(0, rawLineDecorationsWidth.length - 2)); + lineDecorationsWidth = EditorIntOption.clampedInt(multiple * typicalHalfwidthCharacterWidth, 0, 0, 1000); + } else { + lineDecorationsWidth = EditorIntOption.clampedInt(rawLineDecorationsWidth, 0, 0, 1000); + } + if (folding) { + lineDecorationsWidth += 16; + } let lineNumbersWidth = 0; if (showLineNumbers) { @@ -2509,7 +1559,7 @@ export class EditorLayoutProvider { let minimapLeft: number; let minimapWidth: number; let contentWidth: number; - if (!minimap) { + if (!minimapEnabled) { minimapLeft = 0; minimapWidth = 0; renderMinimap = RenderMinimap.None; @@ -2599,6 +1649,944 @@ export class EditorLayoutProvider { } } +//#endregion + +//#region lightbulb + +/** + * Configuration options for editor lightbulb + */ +export interface IEditorLightbulbOptions { + /** + * Enable the lightbulb code action. + * Defaults to true. + */ + enabled?: boolean; +} + +export type EditorLightbulbOptions = Readonly>; + +class EditorLightbulb extends BaseEditorOption { + + constructor() { + const defaults: EditorLightbulbOptions = { enabled: true }; + super( + EditorOption.lightbulb, 'lightbulb', defaults, + { + 'editor.lightbulb.enabled': { + type: 'boolean', + default: defaults.enabled, + description: nls.localize('codeActions', "Enables the code action lightbulb in the editor.") + }, + } + ); + } + + public validate(_input: any): EditorLightbulbOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IEditorLightbulbOptions; + return { + enabled: EditorBooleanOption.boolean(input.enabled, this.defaultValue.enabled) + }; + } +} + +//#endregion + +//#region lineHeight + +class EditorLineHeight extends EditorIntOption { + + constructor() { + super( + EditorOption.lineHeight, 'lineHeight', + EDITOR_FONT_DEFAULTS.lineHeight, 0, 150, + { description: nls.localize('lineHeight', "Controls the line height. Use 0 to compute the line height from the font size.") } + ); + } + + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: number): number { + // The lineHeight is computed from the fontSize if it is 0. + // Moreover, the final lineHeight respects the editor zoom level. + // So take the result from env.fontInfo + return env.fontInfo.lineHeight; + } +} + +//#endregion + +//#region minimap + +/** + * Configuration options for editor minimap + */ +export interface IEditorMinimapOptions { + /** + * Enable the rendering of the minimap. + * Defaults to true. + */ + enabled?: boolean; + /** + * Control the side of the minimap in editor. + * Defaults to 'right'. + */ + side?: 'right' | 'left'; + /** + * Control the rendering of the minimap slider. + * Defaults to 'mouseover'. + */ + showSlider?: 'always' | 'mouseover'; + /** + * Render the actual text on a line (as opposed to color blocks). + * Defaults to true. + */ + renderCharacters?: boolean; + /** + * Limit the width of the minimap to render at most a certain number of columns. + * Defaults to 120. + */ + maxColumn?: number; +} + +export type EditorMinimapOptions = Readonly>; + +class EditorMinimap extends BaseEditorOption { + + constructor() { + const defaults: EditorMinimapOptions = { + enabled: false, // {{SQL CARBON EDIT}} disable minimap by default + side: 'right', + showSlider: 'mouseover', + renderCharacters: true, + maxColumn: 120, + }; + super( + EditorOption.minimap, 'minimap', defaults, + { + 'editor.minimap.enabled': { + type: 'boolean', + default: defaults.enabled, + description: nls.localize('minimap.enabled', "Controls whether the minimap is shown.") + }, + 'editor.minimap.side': { + type: 'string', + enum: ['left', 'right'], + default: defaults.side, + description: nls.localize('minimap.side', "Controls the side where to render the minimap.") + }, + 'editor.minimap.showSlider': { + type: 'string', + enum: ['always', 'mouseover'], + default: defaults.showSlider, + description: nls.localize('minimap.showSlider', "Controls whether the minimap slider is automatically hidden.") + }, + 'editor.minimap.renderCharacters': { + type: 'boolean', + default: defaults.renderCharacters, + description: nls.localize('minimap.renderCharacters', "Render the actual characters on a line as opposed to color blocks.") + }, + 'editor.minimap.maxColumn': { + type: 'number', + default: defaults.maxColumn, + description: nls.localize('minimap.maxColumn', "Limit the width of the minimap to render at most a certain number of columns.") + }, + } + ); + } + + public validate(_input: any): EditorMinimapOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IEditorMinimapOptions; + return { + enabled: EditorBooleanOption.boolean(input.enabled, this.defaultValue.enabled), + side: EditorStringEnumOption.stringSet<'right' | 'left'>(input.side, this.defaultValue.side, ['right', 'left']), + showSlider: EditorStringEnumOption.stringSet<'always' | 'mouseover'>(input.showSlider, this.defaultValue.showSlider, ['always', 'mouseover']), + renderCharacters: EditorBooleanOption.boolean(input.renderCharacters, this.defaultValue.renderCharacters), + maxColumn: EditorIntOption.clampedInt(input.maxColumn, this.defaultValue.maxColumn, 1, 10000), + }; + } +} + +//#endregion + +//#region multiCursorModifier + +function _multiCursorModifierFromString(multiCursorModifier: 'ctrlCmd' | 'alt'): 'altKey' | 'metaKey' | 'ctrlKey' { + if (multiCursorModifier === 'ctrlCmd') { + return (platform.isMacintosh ? 'metaKey' : 'ctrlKey'); + } + return 'altKey'; +} + +//#endregion + +//#region parameterHints + +/** + * Configuration options for parameter hints + */ +export interface IEditorParameterHintOptions { + /** + * Enable parameter hints. + * Defaults to true. + */ + enabled?: boolean; + /** + * Enable cycling of parameter hints. + * Defaults to false. + */ + cycle?: boolean; +} + +export type InternalParameterHintOptions = Readonly>; + +class EditorParameterHints extends BaseEditorOption { + + constructor() { + const defaults: InternalParameterHintOptions = { + enabled: true, + cycle: false + }; + super( + EditorOption.parameterHints, 'parameterHints', defaults, + { + 'editor.parameterHints.enabled': { + type: 'boolean', + default: defaults.enabled, + description: nls.localize('parameterHints.enabled', "Enables a pop-up that shows parameter documentation and type information as you type.") + }, + 'editor.parameterHints.cycle': { + type: 'boolean', + default: defaults.cycle, + description: nls.localize('parameterHints.cycle', "Controls whether the parameter hints menu cycles or closes when reaching the end of the list.") + }, + } + ); + } + + public validate(_input: any): InternalParameterHintOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IEditorParameterHintOptions; + return { + enabled: EditorBooleanOption.boolean(input.enabled, this.defaultValue.enabled), + cycle: EditorBooleanOption.boolean(input.cycle, this.defaultValue.cycle) + }; + } +} + +//#endregion + +//#region pixelRatio + +class EditorPixelRatio extends ComputedEditorOption { + + constructor() { + super(EditorOption.pixelRatio); + } + + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: number): number { + return env.pixelRatio; + } +} + +//#endregion + +//#region quickSuggestions + +/** + * Configuration options for quick suggestions + */ +export interface IQuickSuggestionsOptions { + other: boolean; + comments: boolean; + strings: boolean; +} + +export type ValidQuickSuggestionsOptions = boolean | Readonly>; + +class EditorQuickSuggestions extends BaseEditorOption { + + public readonly defaultValue: Readonly>; + + constructor() { + const defaults: ValidQuickSuggestionsOptions = { + other: true, + comments: false, + strings: false + }; + super( + EditorOption.quickSuggestions, 'quickSuggestions', defaults, + { + anyOf: [ + { + type: 'boolean', + }, + { + type: 'object', + properties: { + strings: { + type: 'boolean', + default: defaults.strings, + description: nls.localize('quickSuggestions.strings', "Enable quick suggestions inside strings.") + }, + comments: { + type: 'boolean', + default: defaults.comments, + description: nls.localize('quickSuggestions.comments', "Enable quick suggestions inside comments.") + }, + other: { + type: 'boolean', + default: defaults.other, + description: nls.localize('quickSuggestions.other', "Enable quick suggestions outside of strings and comments.") + }, + } + } + ], + default: defaults, + description: nls.localize('quickSuggestions', "Controls whether suggestions should automatically show up while typing.") + } + ); + } + + public validate(_input: any): ValidQuickSuggestionsOptions { + if (typeof _input === 'boolean') { + return _input; + } + if (typeof _input === 'object') { + const input = _input as IQuickSuggestionsOptions; + const opts = { + other: EditorBooleanOption.boolean(input.other, this.defaultValue.other), + comments: EditorBooleanOption.boolean(input.comments, this.defaultValue.comments), + strings: EditorBooleanOption.boolean(input.strings, this.defaultValue.strings), + }; + if (opts.other && opts.comments && opts.strings) { + return true; // all on + } else if (!opts.other && !opts.comments && !opts.strings) { + return false; // all off + } else { + return opts; + } + } + return this.defaultValue; + } +} + +//#endregion + +//#region renderLineNumbers + +export type LineNumbersType = 'on' | 'off' | 'relative' | 'interval' | ((lineNumber: number) => string); + +export const enum RenderLineNumbersType { + Off = 0, + On = 1, + Relative = 2, + Interval = 3, + Custom = 4 +} + +export interface InternalEditorRenderLineNumbersOptions { + readonly renderType: RenderLineNumbersType; + readonly renderFn: ((lineNumber: number) => string) | null; +} + +class EditorRenderLineNumbersOption extends BaseEditorOption { + + constructor() { + super( + EditorOption.lineNumbers, 'lineNumbers', { renderType: RenderLineNumbersType.On, renderFn: null }, + { + type: 'string', + enum: ['off', 'on', 'relative', 'interval'], + enumDescriptions: [ + nls.localize('lineNumbers.off', "Line numbers are not rendered."), + nls.localize('lineNumbers.on', "Line numbers are rendered as absolute number."), + nls.localize('lineNumbers.relative', "Line numbers are rendered as distance in lines to cursor position."), + nls.localize('lineNumbers.interval', "Line numbers are rendered every 10 lines.") + ], + default: 'on', + description: nls.localize('lineNumbers', "Controls the display of line numbers.") + } + ); + } + + public validate(lineNumbers: any): InternalEditorRenderLineNumbersOptions { + let renderType: RenderLineNumbersType = this.defaultValue.renderType; + let renderFn: ((lineNumber: number) => string) | null = this.defaultValue.renderFn; + + if (typeof lineNumbers !== 'undefined') { + if (typeof lineNumbers === 'function') { + renderType = RenderLineNumbersType.Custom; + renderFn = lineNumbers; + } else if (lineNumbers === 'interval') { + renderType = RenderLineNumbersType.Interval; + } else if (lineNumbers === 'relative') { + renderType = RenderLineNumbersType.Relative; + } else if (lineNumbers === 'on') { + renderType = RenderLineNumbersType.On; + } else { + renderType = RenderLineNumbersType.Off; + } + } + + return { + renderType, + renderFn + }; + } +} + +//#endregion + +//#region rulers + +class EditorRulers extends SimpleEditorOption { + + constructor() { + const defaults: number[] = []; + super( + EditorOption.rulers, 'rulers', defaults, + { + type: 'array', + items: { + type: 'number' + }, + default: defaults, + description: nls.localize('rulers', "Render vertical rulers after a certain number of monospace characters. Use multiple values for multiple rulers. No rulers are drawn if array is empty.") + } + ); + } + + public validate(input: any): number[] { + if (Array.isArray(input)) { + let rulers: number[] = []; + for (let value of input) { + rulers.push(EditorIntOption.clampedInt(value, 0, 0, 10000)); + } + rulers.sort(); + return rulers; + } + return this.defaultValue; + } +} + +//#endregion + +//#region scrollbar + +/** + * Configuration options for editor scrollbars + */ +export interface IEditorScrollbarOptions { + /** + * The size of arrows (if displayed). + * Defaults to 11. + */ + arrowSize?: number; + /** + * Render vertical scrollbar. + * Defaults to 'auto'. + */ + vertical?: 'auto' | 'visible' | 'hidden'; + /** + * Render horizontal scrollbar. + * Defaults to 'auto'. + */ + horizontal?: 'auto' | 'visible' | 'hidden'; + /** + * Cast horizontal and vertical shadows when the content is scrolled. + * Defaults to true. + */ + useShadows?: boolean; + /** + * Render arrows at the top and bottom of the vertical scrollbar. + * Defaults to false. + */ + verticalHasArrows?: boolean; + /** + * Render arrows at the left and right of the horizontal scrollbar. + * Defaults to false. + */ + horizontalHasArrows?: boolean; + /** + * Listen to mouse wheel events and react to them by scrolling. + * Defaults to true. + */ + handleMouseWheel?: boolean; + /** + * Height in pixels for the horizontal scrollbar. + * Defaults to 10 (px). + */ + horizontalScrollbarSize?: number; + /** + * Width in pixels for the vertical scrollbar. + * Defaults to 10 (px). + */ + verticalScrollbarSize?: number; + /** + * Width in pixels for the vertical slider. + * Defaults to `verticalScrollbarSize`. + */ + verticalSliderSize?: number; + /** + * Height in pixels for the horizontal slider. + * Defaults to `horizontalScrollbarSize`. + */ + horizontalSliderSize?: number; +} + +export interface InternalEditorScrollbarOptions { + readonly arrowSize: number; + readonly vertical: ScrollbarVisibility; + readonly horizontal: ScrollbarVisibility; + readonly useShadows: boolean; + readonly verticalHasArrows: boolean; + readonly horizontalHasArrows: boolean; + readonly handleMouseWheel: boolean; + readonly horizontalScrollbarSize: number; + readonly horizontalSliderSize: number; + readonly verticalScrollbarSize: number; + readonly verticalSliderSize: number; +} + +function _scrollbarVisibilityFromString(visibility: string | undefined, defaultValue: ScrollbarVisibility): ScrollbarVisibility { + if (typeof visibility !== 'string') { + return defaultValue; + } + switch (visibility) { + case 'hidden': return ScrollbarVisibility.Hidden; + case 'visible': return ScrollbarVisibility.Visible; + default: return ScrollbarVisibility.Auto; + } +} + +class EditorScrollbar extends BaseEditorOption { + + constructor() { + super( + EditorOption.scrollbar, 'scrollbar', + { + vertical: ScrollbarVisibility.Auto, + horizontal: ScrollbarVisibility.Auto, + arrowSize: 11, + useShadows: true, + verticalHasArrows: false, + horizontalHasArrows: false, + horizontalScrollbarSize: 10, + horizontalSliderSize: 10, + verticalScrollbarSize: 14, + verticalSliderSize: 14, + handleMouseWheel: true, + } + ); + } + + public validate(_input: any): InternalEditorScrollbarOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IEditorScrollbarOptions; + const horizontalScrollbarSize = EditorIntOption.clampedInt(input.horizontalScrollbarSize, this.defaultValue.horizontalScrollbarSize, 0, 1000); + const verticalScrollbarSize = EditorIntOption.clampedInt(input.verticalScrollbarSize, this.defaultValue.verticalScrollbarSize, 0, 1000); + return { + arrowSize: EditorIntOption.clampedInt(input.arrowSize, this.defaultValue.arrowSize, 0, 1000), + vertical: _scrollbarVisibilityFromString(input.vertical, this.defaultValue.vertical), + horizontal: _scrollbarVisibilityFromString(input.horizontal, this.defaultValue.horizontal), + useShadows: EditorBooleanOption.boolean(input.useShadows, this.defaultValue.useShadows), + verticalHasArrows: EditorBooleanOption.boolean(input.verticalHasArrows, this.defaultValue.verticalHasArrows), + horizontalHasArrows: EditorBooleanOption.boolean(input.horizontalHasArrows, this.defaultValue.horizontalHasArrows), + handleMouseWheel: EditorBooleanOption.boolean(input.handleMouseWheel, this.defaultValue.handleMouseWheel), + horizontalScrollbarSize: horizontalScrollbarSize, + horizontalSliderSize: EditorIntOption.clampedInt(input.horizontalSliderSize, horizontalScrollbarSize, 0, 1000), + verticalScrollbarSize: verticalScrollbarSize, + verticalSliderSize: EditorIntOption.clampedInt(input.verticalSliderSize, verticalScrollbarSize, 0, 1000), + }; + } +} + +//#endregion + +//#region suggest + +/** + * Configuration options for editor suggest widget + */ +export interface ISuggestOptions { + /** + * Enable graceful matching. Defaults to true. + */ + filterGraceful?: boolean; + /** + * Prevent quick suggestions when a snippet is active. Defaults to true. + */ + snippetsPreventQuickSuggestions?: boolean; + /** + * Favours words that appear close to the cursor. + */ + localityBonus?: boolean; + /** + * Enable using global storage for remembering suggestions. + */ + shareSuggestSelections?: boolean; + /** + * Enable or disable icons in suggestions. Defaults to true. + */ + showIcons?: boolean; + /** + * Max suggestions to show in suggestions. Defaults to 12. + */ + maxVisibleSuggestions?: number; + /** + * Names of suggestion types to filter. + */ + filteredTypes?: Record; +} + +export type InternalSuggestOptions = Readonly>; + +class EditorSuggest extends BaseEditorOption { + + constructor() { + const defaults: InternalSuggestOptions = { + filterGraceful: true, + snippetsPreventQuickSuggestions: true, + localityBonus: false, + shareSuggestSelections: false, + showIcons: true, + maxVisibleSuggestions: 12, + filteredTypes: Object.create(null) + }; + super( + EditorOption.suggest, 'suggest', defaults, + { + 'editor.suggest.filterGraceful': { + type: 'boolean', + default: defaults.filterGraceful, + description: nls.localize('suggest.filterGraceful', "Controls whether filtering and sorting suggestions accounts for small typos.") + }, + 'editor.suggest.localityBonus': { + type: 'boolean', + default: defaults.localityBonus, + description: nls.localize('suggest.localityBonus', "Controls whether sorting favours words that appear close to the cursor.") + }, + 'editor.suggest.shareSuggestSelections': { + type: 'boolean', + default: defaults.shareSuggestSelections, + markdownDescription: nls.localize('suggest.shareSuggestSelections', "Controls whether remembered suggestion selections are shared between multiple workspaces and windows (needs `#editor.suggestSelection#`).") + }, + 'editor.suggest.snippetsPreventQuickSuggestions': { + type: 'boolean', + default: defaults.snippetsPreventQuickSuggestions, + description: nls.localize('suggest.snippetsPreventQuickSuggestions', "Control whether an active snippet prevents quick suggestions.") + }, + 'editor.suggest.showIcons': { + type: 'boolean', + default: defaults.showIcons, + description: nls.localize('suggest.showIcons', "Controls whether to show or hide icons in suggestions.") + }, + 'editor.suggest.maxVisibleSuggestions': { + type: 'number', + default: defaults.maxVisibleSuggestions, + minimum: 1, + maximum: 15, + description: nls.localize('suggest.maxVisibleSuggestions', "Controls how many suggestions IntelliSense will show before showing a scrollbar (maximum 15).") + }, + 'editor.suggest.filteredTypes': { + type: 'object', + 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: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.method', "When set to `false` IntelliSense never shows `method` suggestions.") + }, + function: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.function', "When set to `false` IntelliSense never shows `function` suggestions.") + }, + constructor: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.constructor', "When set to `false` IntelliSense never shows `constructor` suggestions.") + }, + field: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.field', "When set to `false` IntelliSense never shows `field` suggestions.") + }, + variable: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.variable', "When set to `false` IntelliSense never shows `variable` suggestions.") + }, + class: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.class', "When set to `false` IntelliSense never shows `class` suggestions.") + }, + struct: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.struct', "When set to `false` IntelliSense never shows `struct` suggestions.") + }, + interface: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.interface', "When set to `false` IntelliSense never shows `interface` suggestions.") + }, + module: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.module', "When set to `false` IntelliSense never shows `module` suggestions.") + }, + property: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.property', "When set to `false` IntelliSense never shows `property` suggestions.") + }, + event: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.event', "When set to `false` IntelliSense never shows `event` suggestions.") + }, + operator: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.operator', "When set to `false` IntelliSense never shows `operator` suggestions.") + }, + unit: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.unit', "When set to `false` IntelliSense never shows `unit` suggestions.") + }, + value: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.value', "When set to `false` IntelliSense never shows `value` suggestions.") + }, + constant: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.constant', "When set to `false` IntelliSense never shows `constant` suggestions.") + }, + enum: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.enum', "When set to `false` IntelliSense never shows `enum` suggestions.") + }, + enumMember: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.enumMember', "When set to `false` IntelliSense never shows `enumMember` suggestions.") + }, + keyword: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.keyword', "When set to `false` IntelliSense never shows `keyword` suggestions.") + }, + text: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.text', "When set to `false` IntelliSense never shows `text` suggestions.") + }, + color: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.color', "When set to `false` IntelliSense never shows `color` suggestions.") + }, + file: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.file', "When set to `false` IntelliSense never shows `file` suggestions.") + }, + reference: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.reference', "When set to `false` IntelliSense never shows `reference` suggestions.") + }, + customcolor: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.customcolor', "When set to `false` IntelliSense never shows `customcolor` suggestions.") + }, + folder: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.folder', "When set to `false` IntelliSense never shows `folder` suggestions.") + }, + typeParameter: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.typeParameter', "When set to `false` IntelliSense never shows `typeParameter` suggestions.") + }, + snippet: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.snippet', "When set to `false` IntelliSense never shows `snippet` suggestions.") + }, + } + }, + } + ); + } + + public validate(_input: any): InternalSuggestOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as ISuggestOptions; + return { + filterGraceful: EditorBooleanOption.boolean(input.filterGraceful, this.defaultValue.filterGraceful), + snippetsPreventQuickSuggestions: EditorBooleanOption.boolean(input.snippetsPreventQuickSuggestions, this.defaultValue.filterGraceful), + localityBonus: EditorBooleanOption.boolean(input.localityBonus, this.defaultValue.localityBonus), + shareSuggestSelections: EditorBooleanOption.boolean(input.shareSuggestSelections, this.defaultValue.shareSuggestSelections), + showIcons: EditorBooleanOption.boolean(input.showIcons, this.defaultValue.showIcons), + maxVisibleSuggestions: EditorIntOption.clampedInt(input.maxVisibleSuggestions, this.defaultValue.maxVisibleSuggestions, 1, 15), + filteredTypes: isObject(input.filteredTypes) ? input.filteredTypes : Object.create(null) + }; + } +} + +//#endregion + +//#region tabFocusMode + +class EditorTabFocusMode extends ComputedEditorOption { + + constructor() { + super(EditorOption.tabFocusMode, [EditorOption.readOnly]); + } + + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: boolean): boolean { + const readOnly = options.get(EditorOption.readOnly); + return (readOnly ? true : env.tabFocusMode); + } +} + +//#endregion + +//#region wrappingIndent + +/** + * Describes how to indent wrapped lines. + */ +export const enum WrappingIndent { + /** + * No indentation => wrapped lines begin at column 1. + */ + None = 0, + /** + * Same => wrapped lines get the same indentation as the parent. + */ + Same = 1, + /** + * Indent => wrapped lines get +1 indentation toward the parent. + */ + Indent = 2, + /** + * DeepIndent => wrapped lines get +2 indentation toward the parent. + */ + DeepIndent = 3 +} + +function _wrappingIndentFromString(wrappingIndent: 'none' | 'same' | 'indent' | 'deepIndent'): WrappingIndent { + switch (wrappingIndent) { + case 'none': return WrappingIndent.None; + case 'same': return WrappingIndent.Same; + case 'indent': return WrappingIndent.Indent; + case 'deepIndent': return WrappingIndent.DeepIndent; + } +} + +//#endregion + +//#region wrappingInfo + +export interface EditorWrappingInfo { + readonly isDominatedByLongLines: boolean; + readonly isWordWrapMinified: boolean; + readonly isViewportWrapping: boolean; + readonly wrappingColumn: number; +} + +class EditorWrappingInfoComputer extends ComputedEditorOption { + + constructor() { + super(EditorOption.wrappingInfo, [EditorOption.wordWrap, EditorOption.wordWrapColumn, EditorOption.wordWrapMinified, EditorOption.layoutInfo, EditorOption.accessibilitySupport]); + } + + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: EditorWrappingInfo): EditorWrappingInfo { + const wordWrap = options.get(EditorOption.wordWrap); + const wordWrapColumn = options.get(EditorOption.wordWrapColumn); + const wordWrapMinified = options.get(EditorOption.wordWrapMinified); + const layoutInfo = options.get(EditorOption.layoutInfo); + const accessibilitySupport = options.get(EditorOption.accessibilitySupport); + + let bareWrappingInfo: { isWordWrapMinified: boolean; isViewportWrapping: boolean; wrappingColumn: number; } | null = null; + { + if (accessibilitySupport === AccessibilitySupport.Enabled) { + // See https://github.com/Microsoft/vscode/issues/27766 + // Never enable wrapping when a screen reader is attached + // because arrow down etc. will not move the cursor in the way + // a screen reader expects. + bareWrappingInfo = { + isWordWrapMinified: false, + isViewportWrapping: false, + wrappingColumn: -1 + }; + } else if (wordWrapMinified && env.isDominatedByLongLines) { + // Force viewport width wrapping if model is dominated by long lines + bareWrappingInfo = { + isWordWrapMinified: true, + isViewportWrapping: true, + wrappingColumn: Math.max(1, layoutInfo.viewportColumn) + }; + } else if (wordWrap === 'on') { + bareWrappingInfo = { + isWordWrapMinified: false, + isViewportWrapping: true, + wrappingColumn: Math.max(1, layoutInfo.viewportColumn) + }; + } else if (wordWrap === 'bounded') { + bareWrappingInfo = { + isWordWrapMinified: false, + isViewportWrapping: true, + wrappingColumn: Math.min(Math.max(1, layoutInfo.viewportColumn), wordWrapColumn) + }; + } else if (wordWrap === 'wordWrapColumn') { + bareWrappingInfo = { + isWordWrapMinified: false, + isViewportWrapping: false, + wrappingColumn: wordWrapColumn + }; + } else { + bareWrappingInfo = { + isWordWrapMinified: false, + isViewportWrapping: false, + wrappingColumn: -1 + }; + } + } + + return { + isDominatedByLongLines: env.isDominatedByLongLines, + isWordWrapMinified: bareWrappingInfo.isWordWrapMinified, + isViewportWrapping: bareWrappingInfo.isViewportWrapping, + wrappingColumn: bareWrappingInfo.wrappingColumn, + }; + } +} + +//#endregion + const DEFAULT_WINDOWS_FONT_FAMILY = 'Consolas, \'Courier New\', monospace'; const DEFAULT_MAC_FONT_FAMILY = 'Menlo, Monaco, \'Courier New\', monospace'; const DEFAULT_LINUX_FONT_FAMILY = '\'Droid Sans Mono\', \'monospace\', monospace, \'Droid Sans Fallback\''; @@ -2635,147 +2623,673 @@ export const EDITOR_MODEL_DEFAULTS = { /** * @internal */ -export const EDITOR_DEFAULTS: IValidatedEditorOptions = { - inDiffEditor: false, - wordSeparators: USUAL_WORD_SEPARATORS, - lineNumbersMinChars: 5, - lineDecorationsWidth: 10, - readOnly: false, - mouseStyle: 'text', - disableLayerHinting: false, - automaticLayout: false, - wordWrap: 'off', - wordWrapColumn: 80, - wordWrapMinified: true, - wrappingIndent: WrappingIndent.Same, - wordWrapBreakBeforeCharacters: '([{‘“〈《「『【〔([{「£¥$£¥++', - wordWrapBreakAfterCharacters: ' \t})]?|/&,;¢°′″‰℃、。。、¢,.:;?!%・・ゝゞヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻ァィゥェォャュョッー”〉》」』】〕)]}」', - wordWrapBreakObtrusiveCharacters: '.', - autoClosingBrackets: 'languageDefined', - autoClosingQuotes: 'languageDefined', - autoClosingOvertype: 'auto', - autoSurround: 'languageDefined', - autoIndent: true, - dragAndDrop: true, - emptySelectionClipboard: true, - copyWithSyntaxHighlighting: true, - useTabStops: true, - multiCursorModifier: 'altKey', - multiCursorMergeOverlapping: true, - accessibilitySupport: 'auto', - showUnused: true, +export const editorOptionsRegistry: IEditorOption[] = []; - viewInfo: { - extraEditorClassName: '', - disableMonospaceOptimizations: false, - rulers: [], - ariaLabel: nls.localize('editorViewAccessibleLabel', "Editor content"), - renderLineNumbers: RenderLineNumbersType.On, - renderCustomLineNumbers: null, - cursorSurroundingLines: 0, - renderFinalNewline: true, - selectOnLineNumbers: true, - glyphMargin: true, - revealHorizontalRightPadding: 30, - roundedSelection: true, - overviewRulerLanes: 2, - overviewRulerBorder: true, - cursorBlinking: TextEditorCursorBlinkingStyle.Blink, - mouseWheelZoom: false, - cursorSmoothCaretAnimation: false, - cursorStyle: TextEditorCursorStyle.Line, - cursorWidth: 0, - hideCursorInOverviewRuler: false, - scrollBeyondLastLine: true, - scrollBeyondLastColumn: 5, - smoothScrolling: false, - stopRenderingLineAfter: 10000, - renderWhitespace: 'none', - renderControlCharacters: false, - fontLigatures: false, - renderIndentGuides: true, - highlightActiveIndentGuide: true, - renderLineHighlight: 'line', - scrollbar: { - vertical: ScrollbarVisibility.Auto, - horizontal: ScrollbarVisibility.Auto, - arrowSize: 11, - useShadows: true, - verticalHasArrows: false, - horizontalHasArrows: false, - horizontalScrollbarSize: 10, - horizontalSliderSize: 10, - verticalScrollbarSize: 14, - verticalSliderSize: 14, - handleMouseWheel: true, - mouseWheelScrollSensitivity: 1, - fastScrollSensitivity: 5, - }, - minimap: { - // {{SQL CARBON EDIT}} - enabled: false, - side: 'right', - showSlider: 'mouseover', - renderCharacters: true, - maxColumn: 120 - }, - fixedOverflowWidgets: false, - }, +function register(option: IEditorOption): IEditorOption { + editorOptionsRegistry[option.id] = option; + return option; +} - contribInfo: { - selectionClipboard: true, - hover: { - enabled: true, - delay: 300, - sticky: true - }, - links: true, - contextmenu: true, - quickSuggestions: { other: true, comments: false, strings: false }, - quickSuggestionsDelay: 10, - parameterHints: { - enabled: true, - cycle: false - }, - formatOnType: false, - formatOnPaste: false, - suggestOnTriggerCharacters: true, - acceptSuggestionOnEnter: 'on', - acceptSuggestionOnCommitCharacter: true, - wordBasedSuggestions: true, - suggestSelection: 'recentlyUsed', - suggestFontSize: 0, - suggestLineHeight: 0, - tabCompletion: 'off', - suggest: { - filterGraceful: true, - snippets: 'inline', - snippetsPreventQuickSuggestions: true, - localityBonus: false, - shareSuggestSelections: false, - showIcons: true, - maxVisibleSuggestions: 12, - filteredTypes: Object.create(null) - }, - gotoLocation: { - multiple: 'peek' - }, - selectionHighlight: true, - occurrencesHighlight: true, - codeLens: true, - folding: true, - foldingStrategy: 'auto', - showFoldingControls: 'mouseover', - matchBrackets: true, - find: { - seedSearchStringFromSelection: true, - autoFindInSelection: false, - globalFindClipboard: false, - addExtraSpaceOnTop: true - }, - colorDecorators: true, - lightbulbEnabled: true, - codeActionsOnSave: {}, - codeActionsOnSaveTimeout: 750 - }, +/** + * @internal + */ +export const enum EditorOption { + acceptSuggestionOnCommitCharacter, + acceptSuggestionOnEnter, + accessibilitySupport, + ariaLabel, + autoClosingBrackets, + autoClosingOvertype, + autoClosingQuotes, + autoIndent, + automaticLayout, + autoSurround, + codeLens, + colorDecorators, + contextmenu, + copyWithSyntaxHighlighting, + cursorBlinking, + cursorSmoothCaretAnimation, + cursorStyle, + cursorSurroundingLines, + cursorWidth, + disableLayerHinting, + disableMonospaceOptimizations, + dragAndDrop, + emptySelectionClipboard, + extraEditorClassName, + fastScrollSensitivity, + find, + fixedOverflowWidgets, + folding, + foldingStrategy, + fontFamily, + fontInfo, + fontLigatures, + fontSize, + fontWeight, + formatOnPaste, + formatOnType, + glyphMargin, + gotoLocation, + hideCursorInOverviewRuler, + highlightActiveIndentGuide, + hover, + inDiffEditor, + letterSpacing, + lightbulb, + lineDecorationsWidth, + lineHeight, + lineNumbers, + lineNumbersMinChars, + links, + matchBrackets, + minimap, + mouseStyle, + mouseWheelScrollSensitivity, + mouseWheelZoom, + multiCursorMergeOverlapping, + multiCursorModifier, + multiCursorPaste, + occurrencesHighlight, + overviewRulerBorder, + overviewRulerLanes, + parameterHints, + quickSuggestions, + quickSuggestionsDelay, + readOnly, + renderControlCharacters, + renderIndentGuides, + renderFinalNewline, + renderLineHighlight, + renderWhitespace, + revealHorizontalRightPadding, + roundedSelection, + rulers, + scrollbar, + scrollBeyondLastColumn, + scrollBeyondLastLine, + selectionClipboard, + selectionHighlight, + selectOnLineNumbers, + showFoldingControls, + showUnused, + snippetSuggestions, + smoothScrolling, + stopRenderingLineAfter, + suggest, + suggestFontSize, + suggestLineHeight, + suggestOnTriggerCharacters, + suggestSelection, + tabCompletion, + useTabStops, + wordSeparators, + wordWrap, + wordWrapBreakAfterCharacters, + wordWrapBreakBeforeCharacters, + wordWrapBreakObtrusiveCharacters, + wordWrapColumn, + wordWrapMinified, + wrappingIndent, + + // Leave these at the end (because they have dependencies!) + editorClassName, + pixelRatio, + tabFocusMode, + layoutInfo, + wrappingInfo, +} + +/** + * @internal + */ +export const EditorOptions = { + acceptSuggestionOnCommitCharacter: register(new EditorBooleanOption( + EditorOption.acceptSuggestionOnCommitCharacter, 'acceptSuggestionOnCommitCharacter', true, + { markdownDescription: nls.localize('acceptSuggestionOnCommitCharacter', "Controls whether suggestions should be accepted on commit characters. For example, in JavaScript, the semi-colon (`;`) can be a commit character that accepts a suggestion and types that character.") } + )), + acceptSuggestionOnEnter: register(new EditorStringEnumOption( + EditorOption.acceptSuggestionOnEnter, 'acceptSuggestionOnEnter', + 'on' as 'on' | 'smart' | 'off', + ['on', 'smart', 'off'] as const, + { + markdownEnumDescriptions: [ + '', + nls.localize('acceptSuggestionOnEnterSmart', "Only accept a suggestion with `Enter` when it makes a textual change."), + '' + ], + markdownDescription: nls.localize('acceptSuggestionOnEnter', "Controls whether suggestions should be accepted on `Enter`, in addition to `Tab`. Helps to avoid ambiguity between inserting new lines or accepting suggestions.") + } + )), + accessibilitySupport: register(new EditorAccessibilitySupport()), + ariaLabel: register(new EditorStringOption( + EditorOption.ariaLabel, 'ariaLabel', nls.localize('editorViewAccessibleLabel', "Editor content") + )), + autoClosingBrackets: register(new EditorStringEnumOption( + EditorOption.autoClosingBrackets, 'autoClosingBrackets', + 'languageDefined' as 'always' | 'languageDefined' | 'beforeWhitespace' | 'never', + ['always', 'languageDefined', 'beforeWhitespace', 'never'] as const, + { + enumDescriptions: [ + '', + nls.localize('editor.autoClosingBrackets.languageDefined', "Use language configurations to determine when to autoclose brackets."), + nls.localize('editor.autoClosingBrackets.beforeWhitespace', "Autoclose brackets only when the cursor is to the left of whitespace."), + '', + ], + description: nls.localize('autoClosingBrackets', "Controls whether the editor should automatically close brackets after the user adds an opening bracket.") + } + )), + autoClosingOvertype: register(new EditorStringEnumOption( + EditorOption.autoClosingOvertype, 'autoClosingOvertype', + 'auto' as 'always' | 'auto' | 'never', + ['always', 'auto', 'never'] as const, + { + enumDescriptions: [ + '', + nls.localize('editor.autoClosingOvertype.auto', "Type over closing quotes or brackets only if they were automatically inserted."), + '', + ], + description: nls.localize('autoClosingOvertype', "Controls whether the editor should type over closing quotes or brackets.") + } + )), + autoClosingQuotes: register(new EditorStringEnumOption( + EditorOption.autoClosingQuotes, 'autoClosingQuotes', + 'languageDefined' as 'always' | 'languageDefined' | 'beforeWhitespace' | 'never', + ['always', 'languageDefined', 'beforeWhitespace', 'never'] as const, + { + enumDescriptions: [ + '', + nls.localize('editor.autoClosingQuotes.languageDefined', "Use language configurations to determine when to autoclose quotes."), + nls.localize('editor.autoClosingQuotes.beforeWhitespace', "Autoclose quotes only when the cursor is to the left of whitespace."), + '', + ], + description: nls.localize('autoClosingQuotes', "Controls whether the editor should automatically close quotes after the user adds an opening quote.") + } + )), + autoIndent: register(new EditorBooleanOption( + EditorOption.autoIndent, 'autoIndent', true, + { description: nls.localize('autoIndent', "Controls whether the editor should automatically adjust the indentation when users type, paste or move lines. Extensions with indentation rules of the language must be available.") } + )), + automaticLayout: register(new EditorBooleanOption( + EditorOption.automaticLayout, 'automaticLayout', false, + )), + autoSurround: register(new EditorStringEnumOption( + EditorOption.autoSurround, 'autoSurround', + 'languageDefined' as 'languageDefined' | 'quotes' | 'brackets' | 'never', + ['languageDefined', 'quotes', 'brackets', 'never'] as const, + { + enumDescriptions: [ + nls.localize('editor.autoSurround.languageDefined', "Use language configurations to determine when to automatically surround selections."), + nls.localize('editor.autoSurround.quotes', "Surround with quotes but not brackets."), + nls.localize('editor.autoSurround.brackets', "Surround with brackets but not quotes."), + '' + ], + description: nls.localize('autoSurround', "Controls whether the editor should automatically surround selections.") + } + )), + codeLens: register(new EditorBooleanOption( + EditorOption.codeLens, 'codeLens', true, + { description: nls.localize('codeLens', "Controls whether the editor shows CodeLens.") } + )), + colorDecorators: register(new EditorBooleanOption( + EditorOption.colorDecorators, 'colorDecorators', true, + { description: nls.localize('colorDecorators', "Controls whether the editor should render the inline color decorators and color picker.") } + )), + contextmenu: register(new EditorBooleanOption( + EditorOption.contextmenu, 'contextmenu', true, + )), + copyWithSyntaxHighlighting: register(new EditorBooleanOption( + EditorOption.copyWithSyntaxHighlighting, 'copyWithSyntaxHighlighting', true, + { description: nls.localize('copyWithSyntaxHighlighting', "Controls whether syntax highlighting should be copied into the clipboard.") } + )), + cursorBlinking: register(new EditorEnumOption( + EditorOption.cursorBlinking, 'cursorBlinking', + TextEditorCursorBlinkingStyle.Blink, 'blink', + ['blink', 'smooth', 'phase', 'expand', 'solid'], + _cursorBlinkingStyleFromString, + { description: nls.localize('cursorBlinking', "Control the cursor animation style.") } + )), + cursorSmoothCaretAnimation: register(new EditorBooleanOption( + EditorOption.cursorSmoothCaretAnimation, 'cursorSmoothCaretAnimation', false, + { description: nls.localize('cursorSmoothCaretAnimation', "Controls whether the smooth caret animation should be enabled.") } + )), + cursorStyle: register(new EditorEnumOption( + EditorOption.cursorStyle, 'cursorStyle', + TextEditorCursorStyle.Line, 'line', + ['line', 'block', 'underline', 'line-thin', 'block-outline', 'underline-thin'], + _cursorStyleFromString, + { description: nls.localize('cursorStyle', "Controls the cursor style.") } + )), + cursorSurroundingLines: register(new EditorIntOption( + EditorOption.cursorSurroundingLines, 'cursorSurroundingLines', + 0, 0, Constants.MAX_SAFE_SMALL_INTEGER, + { description: nls.localize('cursorSurroundingLines', "Controls the minimal number of visible leading and trailing lines surrounding the cursor. Known as 'scrollOff' or `scrollOffset` in some other editors.") } + )), + cursorWidth: register(new EditorIntOption( + EditorOption.cursorWidth, 'cursorWidth', + 0, 0, Constants.MAX_SAFE_SMALL_INTEGER, + { markdownDescription: nls.localize('cursorWidth', "Controls the width of the cursor when `#editor.cursorStyle#` is set to `line`.") } + )), + disableLayerHinting: register(new EditorBooleanOption( + EditorOption.disableLayerHinting, 'disableLayerHinting', false, + )), + disableMonospaceOptimizations: register(new EditorBooleanOption( + EditorOption.disableMonospaceOptimizations, 'disableMonospaceOptimizations', false + )), + dragAndDrop: register(new EditorBooleanOption( + EditorOption.dragAndDrop, 'dragAndDrop', true, + { description: nls.localize('dragAndDrop', "Controls whether the editor should allow moving selections via drag and drop.") } + )), + emptySelectionClipboard: register(new EditorEmptySelectionClipboard()), + extraEditorClassName: register(new EditorStringOption( + EditorOption.extraEditorClassName, 'extraEditorClassName', '', + )), + fastScrollSensitivity: register(new EditorFloatOption( + EditorOption.fastScrollSensitivity, 'fastScrollSensitivity', + 5, x => (x <= 0 ? 5 : x), + { markdownDescription: nls.localize('fastScrollSensitivity', "Scrolling speed multiplier when pressing `Alt`.") } + )), + find: register(new EditorFind()), + fixedOverflowWidgets: register(new EditorBooleanOption( + EditorOption.fixedOverflowWidgets, 'fixedOverflowWidgets', false, + )), + folding: register(new EditorBooleanOption( + EditorOption.folding, 'folding', true, + { description: nls.localize('folding', "Controls whether the editor has code folding enabled.") } + )), + foldingStrategy: register(new EditorStringEnumOption( + EditorOption.foldingStrategy, 'foldingStrategy', + 'auto' as 'auto' | 'indentation', + ['auto', 'indentation'] as const, + { markdownDescription: nls.localize('foldingStrategy', "Controls the strategy for computing folding ranges. `auto` uses a language specific folding strategy, if available. `indentation` uses the indentation based folding strategy.") } + )), + fontFamily: register(new EditorStringOption( + EditorOption.fontFamily, 'fontFamily', EDITOR_FONT_DEFAULTS.fontFamily, + { description: nls.localize('fontFamily', "Controls the font family.") } + )), + fontInfo: register(new EditorFontInfo()), + fontLigatures: register(new EditorBooleanOption( + EditorOption.fontLigatures, 'fontLigatures', false, + { description: nls.localize('fontLigatures', "Enables/Disables font ligatures.") } + )), + fontSize: register(new EditorFontSize()), + fontWeight: register(new EditorStringOption( + EditorOption.fontWeight, 'fontWeight', EDITOR_FONT_DEFAULTS.fontWeight, + { + enum: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'], + description: nls.localize('fontWeight', "Controls the font weight.") + } + )), + formatOnPaste: register(new EditorBooleanOption( + EditorOption.formatOnPaste, 'formatOnPaste', false, + { description: nls.localize('formatOnPaste', "Controls whether the editor should automatically format the pasted content. A formatter must be available and the formatter should be able to format a range in a document.") } + )), + formatOnType: register(new EditorBooleanOption( + EditorOption.formatOnType, 'formatOnType', false, + { description: nls.localize('formatOnType', "Controls whether the editor should automatically format the line after typing.") } + )), + glyphMargin: register(new EditorBooleanOption( + EditorOption.glyphMargin, 'glyphMargin', true, + { description: nls.localize('glyphMargin', "Controls whether the editor should render the vertical glyph margin. Glyph margin is mostly used for debugging.") } + )), + gotoLocation: register(new EditorGoToLocation()), + hideCursorInOverviewRuler: register(new EditorBooleanOption( + EditorOption.hideCursorInOverviewRuler, 'hideCursorInOverviewRuler', false, + { description: nls.localize('hideCursorInOverviewRuler', "Controls whether the cursor should be hidden in the overview ruler.") } + )), + highlightActiveIndentGuide: register(new EditorBooleanOption( + EditorOption.highlightActiveIndentGuide, 'highlightActiveIndentGuide', true, + { description: nls.localize('highlightActiveIndentGuide', "Controls whether the editor should highlight the active indent guide.") } + )), + hover: register(new EditorHover()), + inDiffEditor: register(new EditorBooleanOption( + EditorOption.inDiffEditor, 'inDiffEditor', false, + )), + letterSpacing: register(new EditorFloatOption( + EditorOption.letterSpacing, 'letterSpacing', + EDITOR_FONT_DEFAULTS.letterSpacing, x => EditorFloatOption.clamp(x, -5, 20), + { description: nls.localize('letterSpacing', "Controls the letter spacing in pixels.") } + )), + lightbulb: register(new EditorLightbulb()), + lineDecorationsWidth: register(new SimpleEditorOption(EditorOption.lineDecorationsWidth, 'lineDecorationsWidth', 10 as number | string)), + lineHeight: register(new EditorLineHeight()), + lineNumbers: register(new EditorRenderLineNumbersOption()), + lineNumbersMinChars: register(new EditorIntOption( + EditorOption.lineNumbersMinChars, 'lineNumbersMinChars', + 5, 1, 10 + )), + links: register(new EditorBooleanOption( + EditorOption.links, 'links', true, + { description: nls.localize('links', "Controls whether the editor should detect links and make them clickable.") } + )), + matchBrackets: register(new EditorBooleanOption( + EditorOption.matchBrackets, 'matchBrackets', true, + { description: nls.localize('matchBrackets', "Highlight matching brackets when one of them is selected.") } + )), + minimap: register(new EditorMinimap()), + mouseStyle: register(new EditorStringEnumOption( + EditorOption.mouseStyle, 'mouseStyle', + 'text' as 'text' | 'default' | 'copy', + ['text', 'default', 'copy'] as const, + )), + mouseWheelScrollSensitivity: register(new EditorFloatOption( + EditorOption.mouseWheelScrollSensitivity, 'mouseWheelScrollSensitivity', + 1, x => (x === 0 ? 1 : x), + { markdownDescription: nls.localize('mouseWheelScrollSensitivity', "A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.") } + )), + mouseWheelZoom: register(new EditorBooleanOption( + EditorOption.mouseWheelZoom, 'mouseWheelZoom', false, + { markdownDescription: nls.localize('mouseWheelZoom', "Zoom the font of the editor when using mouse wheel and holding `Ctrl`.") } + )), + multiCursorMergeOverlapping: register(new EditorBooleanOption( + EditorOption.multiCursorMergeOverlapping, 'multiCursorMergeOverlapping', true, + { description: nls.localize('multiCursorMergeOverlapping', "Merge multiple cursors when they are overlapping.") } + )), + multiCursorModifier: register(new EditorEnumOption( + EditorOption.multiCursorModifier, 'multiCursorModifier', + 'altKey', 'alt', + ['ctrlCmd', 'alt'], + _multiCursorModifierFromString, + { + markdownEnumDescriptions: [ + nls.localize('multiCursorModifier.ctrlCmd', "Maps to `Control` on Windows and Linux and to `Command` on macOS."), + nls.localize('multiCursorModifier.alt', "Maps to `Alt` on Windows and Linux and to `Option` on macOS.") + ], + markdownDescription: nls.localize({ + key: 'multiCursorModifier', + comment: [ + '- `ctrlCmd` refers to a value the setting can take and should not be localized.', + '- `Control` and `Command` refer to the modifier keys Ctrl or Cmd on the keyboard and can be localized.' + ] + }, "The modifier to be used to add multiple cursors with the mouse. The Go To Definition and Open Link mouse gestures will adapt such that they do not conflict with the multicursor modifier. [Read more](https://code.visualstudio.com/docs/editor/codebasics#_multicursor-modifier).") + } + )), + multiCursorPaste: register(new EditorStringEnumOption( + EditorOption.multiCursorPaste, 'multiCursorPaste', + 'spread' as 'spread' | 'full', + ['spread', 'full'] as const, + { + markdownEnumDescriptions: [ + nls.localize('multiCursorPaste.spread', "Each cursor pastes a single line of the text."), + nls.localize('multiCursorPaste.full', "Each cursor pastes the full text.") + ], + markdownDescription: nls.localize('multiCursorPaste', "Controls pasting when the line count of the pasted text matches the cursor count.") + } + )), + occurrencesHighlight: register(new EditorBooleanOption( + EditorOption.occurrencesHighlight, 'occurrencesHighlight', true, + { description: nls.localize('occurrencesHighlight', "Controls whether the editor should highlight semantic symbol occurrences.") } + )), + overviewRulerBorder: register(new EditorBooleanOption( + EditorOption.overviewRulerBorder, 'overviewRulerBorder', true, + { description: nls.localize('overviewRulerBorder', "Controls whether a border should be drawn around the overview ruler.") } + )), + overviewRulerLanes: register(new EditorIntOption( + EditorOption.overviewRulerLanes, 'overviewRulerLanes', + 3, 0, 3, + { description: nls.localize('overviewRulerLanes', "Controls the number of decorations that can show up at the same position in the overview ruler.") } + )), + parameterHints: register(new EditorParameterHints()), + quickSuggestions: register(new EditorQuickSuggestions()), + quickSuggestionsDelay: register(new EditorIntOption( + EditorOption.quickSuggestionsDelay, 'quickSuggestionsDelay', + 10, 0, Constants.MAX_SAFE_SMALL_INTEGER, + { description: nls.localize('quickSuggestionsDelay', "Controls the delay in milliseconds after which quick suggestions will show up.") } + )), + readOnly: register(new EditorBooleanOption( + EditorOption.readOnly, 'readOnly', false, + )), + renderControlCharacters: register(new EditorBooleanOption( + EditorOption.renderControlCharacters, 'renderControlCharacters', false, + { description: nls.localize('renderControlCharacters', "Controls whether the editor should render control characters.") } + )), + renderIndentGuides: register(new EditorBooleanOption( + EditorOption.renderIndentGuides, 'renderIndentGuides', true, + { description: nls.localize('renderIndentGuides', "Controls whether the editor should render indent guides.") } + )), + renderFinalNewline: register(new EditorBooleanOption( + EditorOption.renderFinalNewline, 'renderFinalNewline', true, + { description: nls.localize('renderFinalNewline', "Render last line number when the file ends with a newline.") } + )), + renderLineHighlight: register(new EditorStringEnumOption( + EditorOption.renderLineHighlight, 'renderLineHighlight', + 'line' as 'none' | 'gutter' | 'line' | 'all', + ['none', 'gutter', 'line', 'all'] as const, + { + enumDescriptions: [ + '', + '', + '', + nls.localize('renderLineHighlight.all', "Highlights both the gutter and the current line."), + ], + description: nls.localize('renderLineHighlight', "Controls how the editor should render the current line highlight.") + } + )), + renderWhitespace: register(new EditorStringEnumOption( + EditorOption.renderWhitespace, 'renderWhitespace', + 'none' as 'none' | 'boundary' | 'selection' | 'all', + ['none', 'boundary', 'selection', 'all'] as const, + { + enumDescriptions: [ + '', + nls.localize('renderWhitespace.boundary', "Render whitespace characters except for single spaces between words."), + nls.localize('renderWhitespace.selection', "Render whitespace characters only on selected text."), + '' + ], + description: nls.localize('renderWhitespace', "Controls how the editor should render whitespace characters.") + } + )), + revealHorizontalRightPadding: register(new EditorIntOption( + EditorOption.revealHorizontalRightPadding, 'revealHorizontalRightPadding', + 30, 0, 1000, + )), + roundedSelection: register(new EditorBooleanOption( + EditorOption.roundedSelection, 'roundedSelection', true, + { description: nls.localize('roundedSelection', "Controls whether selections should have rounded corners.") } + )), + rulers: register(new EditorRulers()), + scrollbar: register(new EditorScrollbar()), + scrollBeyondLastColumn: register(new EditorIntOption( + EditorOption.scrollBeyondLastColumn, 'scrollBeyondLastColumn', + 5, 0, Constants.MAX_SAFE_SMALL_INTEGER, + { description: nls.localize('scrollBeyondLastColumn', "Controls the number of extra characters beyond which the editor will scroll horizontally.") } + )), + scrollBeyondLastLine: register(new EditorBooleanOption( + EditorOption.scrollBeyondLastLine, 'scrollBeyondLastLine', true, + { description: nls.localize('scrollBeyondLastLine', "Controls whether the editor will scroll beyond the last line.") } + )), + selectionClipboard: register(new EditorBooleanOption( + EditorOption.selectionClipboard, 'selectionClipboard', true, + { + description: nls.localize('selectionClipboard', "Controls whether the Linux primary clipboard should be supported."), + included: platform.isLinux + } + )), + selectionHighlight: register(new EditorBooleanOption( + EditorOption.selectionHighlight, 'selectionHighlight', true, + { description: nls.localize('selectionHighlight', "Controls whether the editor should highlight matches similar to the selection.") } + )), + selectOnLineNumbers: register(new EditorBooleanOption( + EditorOption.selectOnLineNumbers, 'selectOnLineNumbers', true, + )), + showFoldingControls: register(new EditorStringEnumOption( + EditorOption.showFoldingControls, 'showFoldingControls', + 'mouseover' as 'always' | 'mouseover', + ['always', 'mouseover'] as const, + { description: nls.localize('showFoldingControls', "Controls whether the fold controls on the gutter are automatically hidden.") } + )), + showUnused: register(new EditorBooleanOption( + EditorOption.showUnused, 'showUnused', true, + { description: nls.localize('showUnused', "Controls fading out of unused code.") } + )), + snippetSuggestions: register(new EditorStringEnumOption( + EditorOption.snippetSuggestions, 'snippetSuggestions', + 'inline' as 'top' | 'bottom' | 'inline' | 'none', + ['top', 'bottom', 'inline', 'none'] as const, + { + enumDescriptions: [ + nls.localize('snippetSuggestions.top', "Show snippet suggestions on top of other suggestions."), + nls.localize('snippetSuggestions.bottom', "Show snippet suggestions below other suggestions."), + nls.localize('snippetSuggestions.inline', "Show snippets suggestions with other suggestions."), + nls.localize('snippetSuggestions.none', "Do not show snippet suggestions."), + ], + description: nls.localize('snippetSuggestions', "Controls whether snippets are shown with other suggestions and how they are sorted.") + } + )), + smoothScrolling: register(new EditorBooleanOption( + EditorOption.smoothScrolling, 'smoothScrolling', false, + { description: nls.localize('smoothScrolling', "Controls whether the editor will scroll using an animation.") } + )), + stopRenderingLineAfter: register(new EditorIntOption( + EditorOption.stopRenderingLineAfter, 'stopRenderingLineAfter', + 10000, -1, Constants.MAX_SAFE_SMALL_INTEGER, + )), + suggest: register(new EditorSuggest()), + suggestFontSize: register(new EditorIntOption( + EditorOption.suggestFontSize, 'suggestFontSize', + 0, 0, 1000, + { markdownDescription: nls.localize('suggestFontSize', "Font size for the suggest widget. When set to `0`, the value of `#editor.fontSize#` is used.") } + )), + suggestLineHeight: register(new EditorIntOption( + EditorOption.suggestLineHeight, 'suggestLineHeight', + 0, 0, 1000, + { markdownDescription: nls.localize('suggestLineHeight', "Line height for the suggest widget. When set to `0`, the value of `#editor.lineHeight#` is used.") } + )), + suggestOnTriggerCharacters: register(new EditorBooleanOption( + EditorOption.suggestOnTriggerCharacters, 'suggestOnTriggerCharacters', true, + { description: nls.localize('suggestOnTriggerCharacters', "Controls whether suggestions should automatically show up when typing trigger characters.") } + )), + suggestSelection: register(new EditorStringEnumOption( + EditorOption.suggestSelection, 'suggestSelection', + 'recentlyUsed' as 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix', + ['first', 'recentlyUsed', 'recentlyUsedByPrefix'] as const, + { + markdownEnumDescriptions: [ + nls.localize('suggestSelection.first', "Always select the first suggestion."), + nls.localize('suggestSelection.recentlyUsed', "Select recent suggestions unless further typing selects one, e.g. `console.| -> console.log` because `log` has been completed recently."), + nls.localize('suggestSelection.recentlyUsedByPrefix', "Select suggestions based on previous prefixes that have completed those suggestions, e.g. `co -> console` and `con -> const`."), + ], + description: nls.localize('suggestSelection', "Controls how suggestions are pre-selected when showing the suggest list.") + } + )), + tabCompletion: register(new EditorStringEnumOption( + EditorOption.tabCompletion, 'tabCompletion', + 'off' as 'on' | 'off' | 'onlySnippets', + ['on', 'off', 'onlySnippets'] as const, + { + enumDescriptions: [ + nls.localize('tabCompletion.on', "Tab complete will insert the best matching suggestion when pressing tab."), + nls.localize('tabCompletion.off', "Disable tab completions."), + nls.localize('tabCompletion.onlySnippets', "Tab complete snippets when their prefix match. Works best when 'quickSuggestions' aren't enabled."), + ], + description: nls.localize('tabCompletion', "Enables tab completions.") + } + )), + useTabStops: register(new EditorBooleanOption( + EditorOption.useTabStops, 'useTabStops', true, + { description: nls.localize('useTabStops', "Inserting and deleting whitespace follows tab stops.") } + )), + wordSeparators: register(new EditorStringOption( + EditorOption.wordSeparators, 'wordSeparators', USUAL_WORD_SEPARATORS, + { description: nls.localize('wordSeparators', "Characters that will be used as word separators when doing word related navigations or operations.") } + )), + wordWrap: register(new EditorStringEnumOption( + EditorOption.wordWrap, 'wordWrap', + 'off' as 'off' | 'on' | 'wordWrapColumn' | 'bounded', + ['off', 'on', 'wordWrapColumn', 'bounded'] as const, + { + markdownEnumDescriptions: [ + nls.localize('wordWrap.off', "Lines will never wrap."), + nls.localize('wordWrap.on', "Lines will wrap at the viewport width."), + nls.localize({ + key: 'wordWrap.wordWrapColumn', + comment: [ + '- `editor.wordWrapColumn` refers to a different setting and should not be localized.' + ] + }, "Lines will wrap at `#editor.wordWrapColumn#`."), + nls.localize({ + key: 'wordWrap.bounded', + comment: [ + '- viewport means the edge of the visible window size.', + '- `editor.wordWrapColumn` refers to a different setting and should not be localized.' + ] + }, "Lines will wrap at the minimum of viewport and `#editor.wordWrapColumn#`."), + ], + description: nls.localize({ + key: 'wordWrap', + comment: [ + '- \'off\', \'on\', \'wordWrapColumn\' and \'bounded\' refer to values the setting can take and should not be localized.', + '- `editor.wordWrapColumn` refers to a different setting and should not be localized.' + ] + }, "Controls how lines should wrap.") + } + )), + wordWrapBreakAfterCharacters: register(new EditorStringOption( + EditorOption.wordWrapBreakAfterCharacters, 'wordWrapBreakAfterCharacters', + ' \t})]?|/&,;¢°′″‰℃、。。、¢,.:;?!%・・ゝゞヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻ァィゥェォャュョッー”〉》」』】〕)]}」', + )), + wordWrapBreakBeforeCharacters: register(new EditorStringOption( + EditorOption.wordWrapBreakBeforeCharacters, 'wordWrapBreakBeforeCharacters', + '([{‘“〈《「『【〔([{「£¥$£¥++' + )), + wordWrapBreakObtrusiveCharacters: register(new EditorStringOption( + EditorOption.wordWrapBreakObtrusiveCharacters, 'wordWrapBreakObtrusiveCharacters', + '.' + )), + wordWrapColumn: register(new EditorIntOption( + EditorOption.wordWrapColumn, 'wordWrapColumn', + 80, 1, Constants.MAX_SAFE_SMALL_INTEGER, + { + markdownDescription: nls.localize({ + key: 'wordWrapColumn', + comment: [ + '- `editor.wordWrap` refers to a different setting and should not be localized.', + '- \'wordWrapColumn\' and \'bounded\' refer to values the different setting can take and should not be localized.' + ] + }, "Controls the wrapping column of the editor when `#editor.wordWrap#` is `wordWrapColumn` or `bounded`.") + } + )), + wordWrapMinified: register(new EditorBooleanOption( + EditorOption.wordWrapMinified, 'wordWrapMinified', true, + )), + wrappingIndent: register(new EditorEnumOption( + EditorOption.wrappingIndent, 'wrappingIndent', + WrappingIndent.Same, 'same', + ['none', 'same', 'indent', 'deepIndent'], + _wrappingIndentFromString, + { + enumDescriptions: [ + nls.localize('wrappingIndent.none', "No indentation. Wrapped lines begin at column 1."), + nls.localize('wrappingIndent.same', "Wrapped lines get the same indentation as the parent."), + nls.localize('wrappingIndent.indent', "Wrapped lines get +1 indentation toward the parent."), + nls.localize('wrappingIndent.deepIndent', "Wrapped lines get +2 indentation toward the parent."), + ], + description: nls.localize('wrappingIndent', "Controls the indentation of wrapped lines."), + } + )), + + // Leave these at the end (because they have dependencies!) + editorClassName: register(new EditorClassName()), + pixelRatio: register(new EditorPixelRatio()), + tabFocusMode: register(new EditorTabFocusMode()), + layoutInfo: register(new EditorLayoutInfoComputer()), + wrappingInfo: register(new EditorWrappingInfoComputer()), }; + +/** + * @internal + */ +type EditorOptionsType = typeof EditorOptions; +/** + * @internal + */ +type FindEditorOptionsKeyById = { [K in keyof EditorOptionsType]: EditorOptionsType[K]['id'] extends T ? K : never }[keyof EditorOptionsType]; +/** + * @internal + */ +type ComputedEditorOptionValue> = T extends IEditorOption ? R : never; +/** + * @internal + */ +export type FindComputedEditorOptionValueById = NonNullable]>>; diff --git a/src/vs/editor/common/config/fontInfo.ts b/src/vs/editor/common/config/fontInfo.ts index fbdf61b98e..a1e10c1dc6 100644 --- a/src/vs/editor/common/config/fontInfo.ts +++ b/src/vs/editor/common/config/fontInfo.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as platform from 'vs/base/common/platform'; -import { EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; +import { EditorOptions, ValidatedEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { EditorZoom } from 'vs/editor/common/config/editorZoom'; /** @@ -14,59 +14,9 @@ import { EditorZoom } from 'vs/editor/common/config/editorZoom'; const GOLDEN_LINE_HEIGHT_RATIO = platform.isMacintosh ? 1.5 : 1.35; /** - * Font settings maximum and minimum limits + * @internal */ -const MINIMUM_FONT_SIZE = 8; -const MAXIMUM_FONT_SIZE = 100; const MINIMUM_LINE_HEIGHT = 8; -const MAXIMUM_LINE_HEIGHT = 150; -const MINIMUM_LETTER_SPACING = -5; -const MAXIMUM_LETTER_SPACING = 20; - -function safeParseFloat(n: number | string | undefined, defaultValue: number): number { - if (typeof n === 'number') { - return n; - } - if (typeof n === 'undefined') { - return defaultValue; - } - let r = parseFloat(n); - if (isNaN(r)) { - return defaultValue; - } - return r; -} - -function safeParseInt(n: number | string | undefined, defaultValue: number): number { - if (typeof n === 'number') { - return Math.round(n); - } - if (typeof n === 'undefined') { - return defaultValue; - } - let r = parseInt(n); - if (isNaN(r)) { - return defaultValue; - } - return r; -} - -function clamp(n: number, min: number, max: number): number { - if (n < min) { - return min; - } - if (n > max) { - return max; - } - return n; -} - -function _string(value: any, defaultValue: string): string { - if (typeof value !== 'string') { - return defaultValue; - } - return value; -} export class BareFontInfo { readonly _bareFontInfoBrand: void; @@ -74,38 +24,38 @@ export class BareFontInfo { /** * @internal */ - public static createFromRawSettings(opts: { - fontFamily?: string; - fontWeight?: string; - fontSize?: number | string; - lineHeight?: number | string; - letterSpacing?: number | string; - }, zoomLevel: number, ignoreEditorZoom: boolean = false): BareFontInfo { + public static createFromValidatedSettings(options: ValidatedEditorOptions, zoomLevel: number, ignoreEditorZoom: boolean): BareFontInfo { + const fontFamily = options.get(EditorOption.fontFamily); + const fontWeight = options.get(EditorOption.fontWeight); + const fontSize = options.get(EditorOption.fontSize); + const lineHeight = options.get(EditorOption.lineHeight); + const letterSpacing = options.get(EditorOption.letterSpacing); + return BareFontInfo._create(fontFamily, fontWeight, fontSize, lineHeight, letterSpacing, zoomLevel, ignoreEditorZoom); + } - let fontFamily = _string(opts.fontFamily, EDITOR_FONT_DEFAULTS.fontFamily); - let fontWeight = _string(opts.fontWeight, EDITOR_FONT_DEFAULTS.fontWeight); + /** + * @internal + */ + public static createFromRawSettings(opts: { fontFamily?: string; fontWeight?: string; fontSize?: number; lineHeight?: number; letterSpacing?: number; }, zoomLevel: number, ignoreEditorZoom: boolean = false): BareFontInfo { + const fontFamily = EditorOptions.fontFamily.validate(opts.fontFamily); + const fontWeight = EditorOptions.fontWeight.validate(opts.fontWeight); + const fontSize = EditorOptions.fontSize.validate(opts.fontSize); + const lineHeight = EditorOptions.lineHeight.validate(opts.lineHeight); + const letterSpacing = EditorOptions.letterSpacing.validate(opts.letterSpacing); + return BareFontInfo._create(fontFamily, fontWeight, fontSize, lineHeight, letterSpacing, zoomLevel, ignoreEditorZoom); + } - - let fontSize = safeParseFloat(opts.fontSize, EDITOR_FONT_DEFAULTS.fontSize); - fontSize = clamp(fontSize, 0, MAXIMUM_FONT_SIZE); - if (fontSize === 0) { - fontSize = EDITOR_FONT_DEFAULTS.fontSize; - } else if (fontSize < MINIMUM_FONT_SIZE) { - fontSize = MINIMUM_FONT_SIZE; - } - - let lineHeight = safeParseInt(opts.lineHeight, 0); - lineHeight = clamp(lineHeight, 0, MAXIMUM_LINE_HEIGHT); + /** + * @internal + */ + private static _create(fontFamily: string, fontWeight: string, fontSize: number, lineHeight: number, letterSpacing: number, zoomLevel: number, ignoreEditorZoom: boolean): BareFontInfo { if (lineHeight === 0) { lineHeight = Math.round(GOLDEN_LINE_HEIGHT_RATIO * fontSize); } else if (lineHeight < MINIMUM_LINE_HEIGHT) { lineHeight = MINIMUM_LINE_HEIGHT; } - let letterSpacing = safeParseFloat(opts.letterSpacing, 0); - letterSpacing = clamp(letterSpacing, MINIMUM_LETTER_SPACING, MAXIMUM_LETTER_SPACING); - - let editorZoomLevelMultiplier = 1 + (ignoreEditorZoom ? 0 : EditorZoom.getZoomLevel() * 0.1); + const editorZoomLevelMultiplier = 1 + (ignoreEditorZoom ? 0 : EditorZoom.getZoomLevel() * 0.1); fontSize *= editorZoomLevelMultiplier; lineHeight *= editorZoomLevelMultiplier; diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index 6a9eb69ef9..0c09c0de29 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -20,6 +20,7 @@ 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'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; function containsLineMappingChanged(events: viewEvents.ViewEvent[]): boolean { for (let i = 0, len = events.length; i < len; i++) { @@ -295,12 +296,12 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._columnSelectData = columnSelectData; } - public reveal(horizontal: boolean, target: RevealTarget, scrollType: editorCommon.ScrollType): void { - this._revealRange(target, viewEvents.VerticalRevealType.Simple, horizontal, scrollType); + public reveal(source: string, horizontal: boolean, target: RevealTarget, scrollType: editorCommon.ScrollType): void { + this._revealRange(source, target, viewEvents.VerticalRevealType.Simple, horizontal, scrollType); } - public revealRange(revealHorizontal: boolean, viewRange: Range, verticalType: viewEvents.VerticalRevealType, scrollType: editorCommon.ScrollType) { - this.emitCursorRevealRange(viewRange, verticalType, revealHorizontal, scrollType); + public revealRange(source: string, revealHorizontal: boolean, viewRange: Range, verticalType: viewEvents.VerticalRevealType, scrollType: editorCommon.ScrollType) { + this.emitCursorRevealRange(source, viewRange, verticalType, revealHorizontal, scrollType); } public scrollTo(desiredScrollTop: number): void { @@ -371,7 +372,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { } this.setStates('restoreState', CursorChangeReason.NotSet, CursorState.fromModelSelections(desiredSelections)); - this.reveal(true, RevealTarget.Primary, editorCommon.ScrollType.Immediate); + this.reveal('restoreState', true, RevealTarget.Primary, editorCommon.ScrollType.Immediate); } private _onModelContentChanged(hadFlushEvent: boolean): void { @@ -399,7 +400,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { return this._columnSelectData; } const primaryCursor = this._cursors.getPrimaryCursor(); - const primaryPos = primaryCursor.viewState.position; + const primaryPos = primaryCursor.viewState.selectionStart.getStartPosition(); const viewLineNumber = primaryPos.lineNumber; const viewVisualColumn = CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, primaryPos); return { @@ -543,7 +544,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { return true; } - private _revealRange(revealTarget: RevealTarget, verticalType: viewEvents.VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void { + private _revealRange(source: string, revealTarget: RevealTarget, verticalType: viewEvents.VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void { const viewPositions = this._cursors.getViewPositions(); let viewPosition = viewPositions[0]; @@ -568,13 +569,13 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { } const viewRange = new Range(viewPosition.lineNumber, viewPosition.column, viewPosition.lineNumber, viewPosition.column); - this.emitCursorRevealRange(viewRange, verticalType, revealHorizontal, scrollType); + this.emitCursorRevealRange(source, viewRange, verticalType, revealHorizontal, scrollType); } - public emitCursorRevealRange(viewRange: Range, verticalType: viewEvents.VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType) { + public emitCursorRevealRange(source: string, viewRange: Range, verticalType: viewEvents.VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType) { try { const eventsCollector = this._beginEmit(); - eventsCollector.emit(new viewEvents.ViewRevealRangeRequestEvent(viewRange, verticalType, revealHorizontal, scrollType)); + eventsCollector.emit(new viewEvents.ViewRevealRangeRequestEvent(source, viewRange, verticalType, revealHorizontal, scrollType)); } finally { this._endEmit(); } @@ -643,9 +644,17 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { autoClosedEnclosingRanges.push(new Range(lineNumber, openCharIndex + 1, lineNumber, closeCharIndex + 2)); } } - return cursorStateComputer(undoEdits); + const selections = cursorStateComputer(undoEdits); + if (selections) { + // Don't recover the selection from markers because + // we know what it should be. + this._isHandling = true; + } + + return selections; }); if (selections) { + this._isHandling = false; this.setSelections(source, selections); } if (autoClosedCharactersRanges.length > 0) { @@ -665,7 +674,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._isDoingComposition = false; } - if (this._configuration.editor.readOnly) { + if (this._configuration.options.get(EditorOption.readOnly)) { // All the remaining handlers will try to edit the model, // but we cannot edit when read only... this._onDidAttemptReadOnlyEdit.fire(undefined); @@ -740,7 +749,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._validateAutoClosedActions(); if (this._emitStateChangedIfNecessary(source, cursorChangeReason, oldState)) { - this._revealRange(RevealTarget.Primary, viewEvents.VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth); + this._revealRange(source, RevealTarget.Primary, viewEvents.VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth); } } diff --git a/src/vs/editor/common/controller/cursorCommon.ts b/src/vs/editor/common/controller/cursorCommon.ts index 2860c6b6b0..1bd9f55ac4 100644 --- a/src/vs/editor/common/controller/cursorCommon.ts +++ b/src/vs/editor/common/controller/cursorCommon.ts @@ -6,7 +6,7 @@ import { CharCode } from 'vs/base/common/charCode'; import { onUnexpectedError } from 'vs/base/common/errors'; import * as strings from 'vs/base/common/strings'; -import { EditorAutoClosingStrategy, EditorAutoSurroundStrategy, IConfigurationChangedEvent, EditorAutoClosingOvertypeStrategy } from 'vs/editor/common/config/editorOptions'; +import { EditorAutoClosingStrategy, EditorAutoSurroundStrategy, ConfigurationChangedEvent, EditorAutoClosingOvertypeStrategy, EditorOption } from 'vs/editor/common/config/editorOptions'; import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; @@ -55,8 +55,8 @@ export interface ICursors { setColumnSelectData(columnSelectData: IColumnSelectData): void; setStates(source: string, reason: CursorChangeReason, states: PartialCursorState[] | null): void; - reveal(horizontal: boolean, target: RevealTarget, scrollType: ScrollType): void; - revealRange(revealHorizontal: boolean, viewRange: Range, verticalType: VerticalRevealType, scrollType: ScrollType): void; + reveal(source: string, horizontal: boolean, target: RevealTarget, scrollType: ScrollType): void; + revealRange(source: string, revealHorizontal: boolean, viewRange: Range, verticalType: VerticalRevealType, scrollType: ScrollType): void; scrollTo(desiredScrollTop: number): void; @@ -97,6 +97,7 @@ export class CursorConfiguration { public readonly emptySelectionClipboard: boolean; public readonly copyWithSyntaxHighlighting: boolean; public readonly multiCursorMergeOverlapping: boolean; + public readonly multiCursorPaste: 'spread' | 'full'; public readonly autoClosingBrackets: EditorAutoClosingStrategy; public readonly autoClosingQuotes: EditorAutoClosingStrategy; public readonly autoClosingOvertype: EditorAutoClosingOvertypeStrategy; @@ -110,19 +111,20 @@ export class CursorConfiguration { private readonly _languageIdentifier: LanguageIdentifier; private _electricChars: { [key: string]: boolean; } | null; - public static shouldRecreate(e: IConfigurationChangedEvent): boolean { + public static shouldRecreate(e: ConfigurationChangedEvent): boolean { return ( - e.layoutInfo - || e.wordSeparators - || e.emptySelectionClipboard - || e.multiCursorMergeOverlapping - || e.autoClosingBrackets - || e.autoClosingQuotes - || e.autoClosingOvertype - || e.autoSurround - || e.useTabStops - || e.lineHeight - || e.readOnly + e.hasChanged(EditorOption.layoutInfo) + || e.hasChanged(EditorOption.wordSeparators) + || e.hasChanged(EditorOption.emptySelectionClipboard) + || e.hasChanged(EditorOption.multiCursorMergeOverlapping) + || e.hasChanged(EditorOption.multiCursorPaste) + || e.hasChanged(EditorOption.autoClosingBrackets) + || e.hasChanged(EditorOption.autoClosingQuotes) + || e.hasChanged(EditorOption.autoClosingOvertype) + || e.hasChanged(EditorOption.autoSurround) + || e.hasChanged(EditorOption.useTabStops) + || e.hasChanged(EditorOption.lineHeight) + || e.hasChanged(EditorOption.readOnly) ); } @@ -133,24 +135,26 @@ export class CursorConfiguration { ) { this._languageIdentifier = languageIdentifier; - let c = configuration.editor; + const options = configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); - this.readOnly = c.readOnly; + this.readOnly = options.get(EditorOption.readOnly); this.tabSize = modelOptions.tabSize; this.indentSize = modelOptions.indentSize; this.insertSpaces = modelOptions.insertSpaces; - this.pageSize = Math.max(1, Math.floor(c.layoutInfo.height / c.fontInfo.lineHeight) - 2); - this.lineHeight = c.lineHeight; - this.useTabStops = c.useTabStops; - this.wordSeparators = c.wordSeparators; - this.emptySelectionClipboard = c.emptySelectionClipboard; - this.copyWithSyntaxHighlighting = c.copyWithSyntaxHighlighting; - this.multiCursorMergeOverlapping = c.multiCursorMergeOverlapping; - this.autoClosingBrackets = c.autoClosingBrackets; - this.autoClosingQuotes = c.autoClosingQuotes; - this.autoClosingOvertype = c.autoClosingOvertype; - this.autoSurround = c.autoSurround; - this.autoIndent = c.autoIndent; + this.lineHeight = options.get(EditorOption.lineHeight); + this.pageSize = Math.max(1, Math.floor(layoutInfo.height / this.lineHeight) - 2); + this.useTabStops = options.get(EditorOption.useTabStops); + this.wordSeparators = options.get(EditorOption.wordSeparators); + this.emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard); + this.copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting); + this.multiCursorMergeOverlapping = options.get(EditorOption.multiCursorMergeOverlapping); + this.multiCursorPaste = options.get(EditorOption.multiCursorPaste); + this.autoClosingBrackets = options.get(EditorOption.autoClosingBrackets); + this.autoClosingQuotes = options.get(EditorOption.autoClosingQuotes); + this.autoClosingOvertype = options.get(EditorOption.autoClosingOvertype); + this.autoSurround = options.get(EditorOption.autoSurround); + this.autoIndent = options.get(EditorOption.autoIndent); this.autoClosingPairsOpen2 = new Map(); this.autoClosingPairsClose2 = new Map(); diff --git a/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts index d08ebd078f..562be37c99 100644 --- a/src/vs/editor/common/controller/cursorTypeOperations.ts +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -105,7 +105,7 @@ export class TypeOperations { }); } - private static _distributePasteToCursors(selections: Selection[], text: string, pasteOnNewLine: boolean, multicursorText: string[]): string[] | null { + private static _distributePasteToCursors(config: CursorConfiguration, selections: Selection[], text: string, pasteOnNewLine: boolean, multicursorText: string[]): string[] | null { if (pasteOnNewLine) { return null; } @@ -118,20 +118,27 @@ export class TypeOperations { return multicursorText; } - // Remove trailing \n if present - if (text.charCodeAt(text.length - 1) === CharCode.LineFeed) { - text = text.substr(0, text.length - 1); - } - let lines = text.split(/\r\n|\r|\n/); - if (lines.length === selections.length) { - return lines; + if (config.multiCursorPaste === 'spread') { + // Try to spread the pasted text in case the line count matches the cursor count + // Remove trailing \n if present + if (text.charCodeAt(text.length - 1) === CharCode.LineFeed) { + text = text.substr(0, text.length - 1); + } + // Remove trailing \r if present + if (text.charCodeAt(text.length - 1) === CharCode.CarriageReturn) { + text = text.substr(0, text.length - 1); + } + let lines = text.split(/\r\n|\r|\n/); + if (lines.length === selections.length) { + return lines; + } } return null; } public static paste(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[], text: string, pasteOnNewLine: boolean, multicursorText: string[]): EditOperationResult { - const distributedPaste = this._distributePasteToCursors(selections, text, pasteOnNewLine, multicursorText); + const distributedPaste = this._distributePasteToCursors(config, selections, text, pasteOnNewLine, multicursorText); if (distributedPaste) { selections = selections.sort(Range.compareRangesUsingStarts); diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index 601b472fe9..63fc4720df 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -6,7 +6,7 @@ import { IMarkdownString } from 'vs/base/common/htmlContent'; import { IDisposable } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, IComputedEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; @@ -149,13 +149,13 @@ export interface ILineChange extends IChange { * @internal */ export interface IConfiguration extends IDisposable { - onDidChange(listener: (e: editorOptions.IConfigurationChangedEvent) => void): IDisposable; + onDidChange(listener: (e: ConfigurationChangedEvent) => void): IDisposable; - readonly editor: editorOptions.InternalEditorOptions; + readonly options: IComputedEditorOptions; setMaxLineNumber(maxLineNumber: number): void; - updateOptions(newOptions: editorOptions.IEditorOptions): void; - getRawOptions(): editorOptions.IEditorOptions; + updateOptions(newOptions: IEditorOptions): void; + getRawOptions(): IEditorOptions; observeReferenceElement(dimension?: IDimension): void; setIsDominatedByLongLines(isDominatedByLongLines: boolean): void; } @@ -263,7 +263,7 @@ export interface IEditor { /** * Update the editor's options after the editor has been created. */ - updateOptions(newOptions: editorOptions.IEditorOptions): void; + updateOptions(newOptions: IEditorOptions): void; /** * Indicates that the editor becomes visible. diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index a918fd0591..8a94c5a8f7 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -2621,8 +2621,8 @@ class DecorationOptions implements model.IDecorationOptions { readonly darkColor: string | ThemeColor; constructor(options: model.IDecorationOptions) { - this.color = options.color || strings.empty; - this.darkColor = options.darkColor || strings.empty; + this.color = options.color || ''; + this.darkColor = options.darkColor || ''; } } @@ -2658,7 +2658,7 @@ export class ModelDecorationOverviewRulerOptions extends DecorationOptions { } let c = color ? theme.getColor(color.id) : null; if (!c) { - return strings.empty; + return ''; } return c.toString(); } diff --git a/src/vs/editor/common/model/textModelSearch.ts b/src/vs/editor/common/model/textModelSearch.ts index e2ebdf719d..c7506a99ed 100644 --- a/src/vs/editor/common/model/textModelSearch.ts +++ b/src/vs/editor/common/model/textModelSearch.ts @@ -45,7 +45,8 @@ export class SearchParams { matchCase: this.matchCase, wholeWord: false, multiline: multiline, - global: true + global: true, + unicode: true }); } catch (err) { return null; diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 9ab3fd7033..04ed7f4b88 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1402,6 +1402,15 @@ export interface IWebviewPanelOptions { readonly retainContextWhenHidden?: boolean; } +/** + * @internal + */ +export const enum WebviewEditorState { + Readonly = 1, + Unchanged = 2, + Dirty = 3, +} + export interface CodeLens { range: IRange; id?: string; diff --git a/src/vs/editor/common/services/editorWorkerService.ts b/src/vs/editor/common/services/editorWorkerService.ts index 6d5a25341f..d1b4b0829f 100644 --- a/src/vs/editor/common/services/editorWorkerService.ts +++ b/src/vs/editor/common/services/editorWorkerService.ts @@ -18,7 +18,7 @@ export interface IDiffComputationResult { } export interface IEditorWorkerService { - _serviceBrand: any; + _serviceBrand: undefined; canComputeDiff(original: URI, modified: URI): boolean; computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise; diff --git a/src/vs/editor/common/services/editorWorkerServiceImpl.ts b/src/vs/editor/common/services/editorWorkerServiceImpl.ts index 30192baec2..fb44928dfe 100644 --- a/src/vs/editor/common/services/editorWorkerServiceImpl.ts +++ b/src/vs/editor/common/services/editorWorkerServiceImpl.ts @@ -8,7 +8,6 @@ import { Disposable, IDisposable, dispose, toDisposable, DisposableStore } from import { URI } from 'vs/base/common/uri'; import { SimpleWorkerClient, logOnceWebWorkerWarning, IWorkerClient } from 'vs/base/common/worker/simpleWorker'; import { DefaultWorkerFactory } from 'vs/base/worker/defaultWorkerFactory'; -import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; @@ -46,7 +45,7 @@ function canSyncModel(modelService: IModelService, resource: URI): boolean { } export class EditorWorkerServiceImpl extends Disposable implements IEditorWorkerService { - public _serviceBrand: any; + public _serviceBrand: undefined; private readonly _modelService: IModelService; private readonly _workerManager: WorkerManager; @@ -146,7 +145,7 @@ class WordBasedCompletionItemProvider implements modes.CompletionItemProvider { } provideCompletionItems(model: ITextModel, position: Position): Promise | undefined { - const { wordBasedSuggestions } = this._configurationService.getValue(model.uri, position, 'editor'); + const { wordBasedSuggestions } = this._configurationService.getValue<{ wordBasedSuggestions?: boolean }>(model.uri, position, 'editor'); if (!wordBasedSuggestions) { return undefined; } diff --git a/src/vs/editor/common/services/markerDecorationsServiceImpl.ts b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts index 3c040747c4..ef3f7fa7b2 100644 --- a/src/vs/editor/common/services/markerDecorationsServiceImpl.ts +++ b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts @@ -61,7 +61,7 @@ class MarkerDecorations extends Disposable { export class MarkerDecorationsService extends Disposable implements IMarkerDecorationsService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _onDidChangeMarker = this._register(new Emitter()); readonly onDidChangeMarker: Event = this._onDidChangeMarker.event; diff --git a/src/vs/editor/common/services/markersDecorationService.ts b/src/vs/editor/common/services/markersDecorationService.ts index 339f911e47..0be1f271e5 100644 --- a/src/vs/editor/common/services/markersDecorationService.ts +++ b/src/vs/editor/common/services/markersDecorationService.ts @@ -12,7 +12,7 @@ import { Range } from 'vs/editor/common/core/range'; export const IMarkerDecorationsService = createDecorator('markerDecorationsService'); export interface IMarkerDecorationsService { - _serviceBrand: any; + _serviceBrand: undefined; onDidChangeMarker: Event; diff --git a/src/vs/editor/common/services/modeService.ts b/src/vs/editor/common/services/modeService.ts index 3e60e3b1a1..c421bdd514 100644 --- a/src/vs/editor/common/services/modeService.ts +++ b/src/vs/editor/common/services/modeService.ts @@ -28,7 +28,7 @@ export interface ILanguageSelection extends IDisposable { } export interface IModeService { - _serviceBrand: any; + _serviceBrand: undefined; onDidCreateMode: Event; diff --git a/src/vs/editor/common/services/modeServiceImpl.ts b/src/vs/editor/common/services/modeServiceImpl.ts index f457fd470d..12aa78b072 100644 --- a/src/vs/editor/common/services/modeServiceImpl.ts +++ b/src/vs/editor/common/services/modeServiceImpl.ts @@ -40,7 +40,7 @@ class LanguageSelection extends Disposable implements ILanguageSelection { } export class ModeServiceImpl implements IModeService { - public _serviceBrand: any; + public _serviceBrand: undefined; private readonly _instantiatedModes: { [modeId: string]: IMode; }; private readonly _registry: LanguagesRegistry; diff --git a/src/vs/editor/common/services/modelService.ts b/src/vs/editor/common/services/modelService.ts index 6b596e6636..d2d09a6f31 100644 --- a/src/vs/editor/common/services/modelService.ts +++ b/src/vs/editor/common/services/modelService.ts @@ -12,7 +12,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export const IModelService = createDecorator('modelService'); export interface IModelService { - _serviceBrand: any; + _serviceBrand: undefined; createModel(value: string | ITextBufferFactory, languageSelection: ILanguageSelection | null, resource?: URI, isForSimpleWidget?: boolean): ITextModel; diff --git a/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts index 64a369660a..049e6879b6 100644 --- a/src/vs/editor/common/services/modelServiceImpl.ts +++ b/src/vs/editor/common/services/modelServiceImpl.ts @@ -88,7 +88,7 @@ interface IRawConfig { const DEFAULT_EOL = (platform.isLinux || platform.isMacintosh) ? DefaultEndOfLine.LF : DefaultEndOfLine.CRLF; export class ModelServiceImpl extends Disposable implements IModelService { - public _serviceBrand: any; + public _serviceBrand: undefined; private readonly _configurationService: IConfigurationService; private readonly _configurationServiceSubscription: IDisposable; diff --git a/src/vs/editor/common/services/resolverService.ts b/src/vs/editor/common/services/resolverService.ts index 9c8539f62b..92e21e8984 100644 --- a/src/vs/editor/common/services/resolverService.ts +++ b/src/vs/editor/common/services/resolverService.ts @@ -12,7 +12,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export const ITextModelService = createDecorator('textModelService'); export interface ITextModelService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Provided a resource URI, it will return a model reference diff --git a/src/vs/editor/common/services/resourceConfiguration.ts b/src/vs/editor/common/services/resourceConfiguration.ts index 7cdd6a6c7e..e44a924d89 100644 --- a/src/vs/editor/common/services/resourceConfiguration.ts +++ b/src/vs/editor/common/services/resourceConfiguration.ts @@ -13,7 +13,7 @@ export const ITextResourceConfigurationService = createDecorator = this._register(new Emitter()); public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index 232b3dabfc..dd85ebebe0 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -332,34 +332,13 @@ export enum CursorChangeReason { Redo = 6 } -export enum RenderMinimap { - None = 0, - Small = 1, - Large = 2, - SmallBlocks = 3, - LargeBlocks = 4 -} - -/** - * Describes how to indent wrapped lines. - */ -export enum WrappingIndent { +export enum AccessibilitySupport { /** - * No indentation => wrapped lines begin at column 1. + * This should be the browser case where it is not known if a screen reader is attached or no. */ - None = 0, - /** - * Same => wrapped lines get the same indentation as the parent. - */ - Same = 1, - /** - * Indent => wrapped lines get +1 indentation toward the parent. - */ - Indent = 2, - /** - * DeepIndent => wrapped lines get +2 indentation toward the parent. - */ - DeepIndent = 3 + Unknown = 0, + Disabled = 1, + Enabled = 2 } /** @@ -422,6 +401,14 @@ export enum TextEditorCursorStyle { UnderlineThin = 6 } +export enum RenderMinimap { + None = 0, + Small = 1, + Large = 2, + SmallBlocks = 3, + LargeBlocks = 4 +} + export enum RenderLineNumbersType { Off = 0, On = 1, @@ -430,6 +417,28 @@ export enum RenderLineNumbersType { Custom = 4 } +/** + * Describes how to indent wrapped lines. + */ +export enum WrappingIndent { + /** + * No indentation => wrapped lines begin at column 1. + */ + None = 0, + /** + * Same => wrapped lines get the same indentation as the parent. + */ + Same = 1, + /** + * Indent => wrapped lines get +1 indentation toward the parent. + */ + Indent = 2, + /** + * DeepIndent => wrapped lines get +2 indentation toward the parent. + */ + DeepIndent = 3 +} + /** * A positioning preference for rendering content widgets. */ diff --git a/src/vs/editor/common/view/viewEvents.ts b/src/vs/editor/common/view/viewEvents.ts index 6b4eb7ef1a..4b8773b80b 100644 --- a/src/vs/editor/common/view/viewEvents.ts +++ b/src/vs/editor/common/view/viewEvents.ts @@ -6,7 +6,7 @@ import * as errors from 'vs/base/common/errors'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ScrollEvent } from 'vs/base/common/scrollable'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { ScrollType } from 'vs/editor/common/editorCommon'; @@ -34,32 +34,14 @@ export class ViewConfigurationChangedEvent { public readonly type = ViewEventType.ViewConfigurationChanged; - public readonly canUseLayerHinting: boolean; - public readonly pixelRatio: boolean; - public readonly editorClassName: boolean; - public readonly lineHeight: boolean; - public readonly readOnly: boolean; - public readonly accessibilitySupport: boolean; - public readonly emptySelectionClipboard: boolean; - public readonly copyWithSyntaxHighlighting: boolean; - public readonly layoutInfo: boolean; - public readonly fontInfo: boolean; - public readonly viewInfo: boolean; - public readonly wrappingInfo: boolean; + public readonly _source: ConfigurationChangedEvent; - constructor(source: IConfigurationChangedEvent) { - this.canUseLayerHinting = source.canUseLayerHinting; - this.pixelRatio = source.pixelRatio; - this.editorClassName = source.editorClassName; - this.lineHeight = source.lineHeight; - this.readOnly = source.readOnly; - this.accessibilitySupport = source.accessibilitySupport; - this.emptySelectionClipboard = source.emptySelectionClipboard; - this.copyWithSyntaxHighlighting = source.copyWithSyntaxHighlighting; - this.layoutInfo = source.layoutInfo; - this.fontInfo = source.fontInfo; - this.viewInfo = source.viewInfo; - this.wrappingInfo = source.wrappingInfo; + constructor(source: ConfigurationChangedEvent) { + this._source = source; + } + + public hasChanged(id: EditorOption): boolean { + return this._source.hasChanged(id); } } @@ -198,7 +180,13 @@ export class ViewRevealRangeRequestEvent { public readonly scrollType: ScrollType; - constructor(range: Range, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: ScrollType) { + /** + * Source of the call that caused the event. + */ + readonly source: string; + + constructor(source: string, range: Range, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: ScrollType) { + this.source = source; this.range = range; this.verticalType = verticalType; this.revealHorizontal = revealHorizontal; diff --git a/src/vs/editor/common/viewLayout/viewLayout.ts b/src/vs/editor/common/viewLayout/viewLayout.ts index 22635b7f4f..a3c61eb31b 100644 --- a/src/vs/editor/common/viewLayout/viewLayout.ts +++ b/src/vs/editor/common/viewLayout/viewLayout.ts @@ -6,7 +6,7 @@ import { Event } from 'vs/base/common/event'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { IScrollDimensions, IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { LinesLayout } from 'vs/editor/common/viewLayout/linesLayout'; import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; @@ -27,14 +27,17 @@ export class ViewLayout extends Disposable implements IViewLayout { super(); this._configuration = configuration; - this._linesLayout = new LinesLayout(lineCount, this._configuration.editor.lineHeight); + const options = this._configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._linesLayout = new LinesLayout(lineCount, options.get(EditorOption.lineHeight)); this.scrollable = this._register(new Scrollable(0, scheduleAtNextAnimationFrame)); this._configureSmoothScrollDuration(); this.scrollable.setScrollDimensions({ - width: configuration.editor.layoutInfo.contentWidth, - height: configuration.editor.layoutInfo.contentHeight + width: layoutInfo.contentWidth, + height: layoutInfo.contentHeight }); this.onDidScroll = this.scrollable.onScroll; @@ -50,22 +53,24 @@ export class ViewLayout extends Disposable implements IViewLayout { } private _configureSmoothScrollDuration(): void { - this.scrollable.setSmoothScrollDuration(this._configuration.editor.viewInfo.smoothScrolling ? SMOOTH_SCROLLING_TIME : 0); + this.scrollable.setSmoothScrollDuration(this._configuration.options.get(EditorOption.smoothScrolling) ? SMOOTH_SCROLLING_TIME : 0); } // ---- begin view event handlers - public onConfigurationChanged(e: IConfigurationChangedEvent): void { - if (e.lineHeight) { - this._linesLayout.setLineHeight(this._configuration.editor.lineHeight); + public onConfigurationChanged(e: ConfigurationChangedEvent): void { + const options = this._configuration.options; + if (e.hasChanged(EditorOption.lineHeight)) { + this._linesLayout.setLineHeight(options.get(EditorOption.lineHeight)); } - if (e.layoutInfo) { + if (e.hasChanged(EditorOption.layoutInfo)) { + const layoutInfo = options.get(EditorOption.layoutInfo); this.scrollable.setScrollDimensions({ - width: this._configuration.editor.layoutInfo.contentWidth, - height: this._configuration.editor.layoutInfo.contentHeight + width: layoutInfo.contentWidth, + height: layoutInfo.contentHeight }); } - if (e.viewInfo) { + if (e.hasChanged(EditorOption.smoothScrolling)) { this._configureSmoothScrollDuration(); } this._updateHeight(); @@ -83,7 +88,9 @@ export class ViewLayout extends Disposable implements IViewLayout { // ---- end view event handlers private _getHorizontalScrollbarHeight(scrollDimensions: IScrollDimensions): number { - if (this._configuration.editor.viewInfo.scrollbar.horizontal === ScrollbarVisibility.Hidden) { + const options = this._configuration.options; + const scrollbar = options.get(EditorOption.scrollbar); + if (scrollbar.horizontal === ScrollbarVisibility.Hidden) { // horizontal scrollbar not visible return 0; } @@ -91,15 +98,16 @@ export class ViewLayout extends Disposable implements IViewLayout { // horizontal scrollbar not visible return 0; } - return this._configuration.editor.viewInfo.scrollbar.horizontalScrollbarSize; + return scrollbar.horizontalScrollbarSize; } private _getTotalHeight(): number { + const options = this._configuration.options; const scrollDimensions = this.scrollable.getScrollDimensions(); let result = this._linesLayout.getLinesTotalHeight(); - if (this._configuration.editor.viewInfo.scrollBeyondLastLine) { - result += scrollDimensions.height - this._configuration.editor.lineHeight; + if (options.get(EditorOption.scrollBeyondLastLine)) { + result += scrollDimensions.height - options.get(EditorOption.lineHeight); } else { result += this._getHorizontalScrollbarHeight(scrollDimensions); } @@ -138,9 +146,11 @@ export class ViewLayout extends Disposable implements IViewLayout { } private _computeScrollWidth(maxLineWidth: number, viewportWidth: number): number { - let isViewportWrapping = this._configuration.editor.wrappingInfo.isViewportWrapping; + const options = this._configuration.options; + const wrappingInfo = options.get(EditorOption.wrappingInfo); + let isViewportWrapping = wrappingInfo.isViewportWrapping; if (!isViewportWrapping) { - const extraHorizontalSpace = this._configuration.editor.viewInfo.scrollBeyondLastColumn * this._configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; + const extraHorizontalSpace = options.get(EditorOption.scrollBeyondLastColumn) * options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; const whitespaceMinWidth = this._linesLayout.getWhitespaceMinWidth(); return Math.max(maxLineWidth + extraHorizontalSpace, viewportWidth, whitespaceMinWidth); } diff --git a/src/vs/editor/common/viewModel/viewModelDecorations.ts b/src/vs/editor/common/viewModel/viewModelDecorations.ts index cc1cf1a573..54c1a9da27 100644 --- a/src/vs/editor/common/viewModel/viewModelDecorations.ts +++ b/src/vs/editor/common/viewModel/viewModelDecorations.ts @@ -10,6 +10,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { IModelDecoration, ITextModel } from 'vs/editor/common/model'; import { IViewModelLinesCollection } from 'vs/editor/common/viewModel/splitLinesCollection'; import { ICoordinatesConverter, InlineDecoration, InlineDecorationType, ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface IDecorationsViewportData { /** @@ -103,7 +104,7 @@ export class ViewModelDecorations implements IDisposable { } private _getDecorationsViewportData(viewportRange: Range): IDecorationsViewportData { - const modelDecorations = this._linesCollection.getDecorationsInRange(viewportRange, this.editorId, this.configuration.editor.readOnly); + const modelDecorations = this._linesCollection.getDecorationsInRange(viewportRange, this.editorId, this.configuration.options.get(EditorOption.readOnly)); const startLineNumber = viewportRange.startLineNumber; const endLineNumber = viewportRange.endLineNumber; diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index 64924cd197..b236398437 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -6,7 +6,7 @@ import { Color } from 'vs/base/common/color'; import { IDisposable } from 'vs/base/common/lifecycle'; import * as strings from 'vs/base/common/strings'; -import { IConfigurationChangedEvent, EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EDITOR_FONT_DEFAULTS, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; @@ -59,21 +59,27 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel this.lines = new IdentityLinesCollection(this.model); } else { - const conf = this.configuration.editor; + const options = this.configuration.options; + const wrappingInfo = options.get(EditorOption.wrappingInfo); + const fontInfo = options.get(EditorOption.fontInfo); + const wordWrapBreakAfterCharacters = options.get(EditorOption.wordWrapBreakAfterCharacters); + const wordWrapBreakBeforeCharacters = options.get(EditorOption.wordWrapBreakBeforeCharacters); + const wordWrapBreakObtrusiveCharacters = options.get(EditorOption.wordWrapBreakObtrusiveCharacters); + const wrappingIndent = options.get(EditorOption.wrappingIndent); let hardWrappingLineMapperFactory = new CharacterHardWrappingLineMapperFactory( - conf.wrappingInfo.wordWrapBreakBeforeCharacters, - conf.wrappingInfo.wordWrapBreakAfterCharacters, - conf.wrappingInfo.wordWrapBreakObtrusiveCharacters + wordWrapBreakBeforeCharacters, + wordWrapBreakAfterCharacters, + wordWrapBreakObtrusiveCharacters ); this.lines = new SplitLinesCollection( this.model, hardWrappingLineMapperFactory, this.model.getOptions().tabSize, - conf.wrappingInfo.wrappingColumn, - conf.fontInfo.typicalFullwidthCharacterWidth / conf.fontInfo.typicalHalfwidthCharacterWidth, - conf.wrappingInfo.wrappingIndent + wrappingInfo.wrappingColumn, + fontInfo.typicalFullwidthCharacterWidth / fontInfo.typicalHalfwidthCharacterWidth, + wrappingIndent ); } @@ -136,7 +142,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel this.hasFocus = hasFocus; } - private _onConfigurationChanged(eventsCollector: viewEvents.ViewEventsCollector, e: IConfigurationChangedEvent): void { + private _onConfigurationChanged(eventsCollector: viewEvents.ViewEventsCollector, e: ConfigurationChangedEvent): void { // We might need to restore the current centered view range, so save it (if available) let previousViewportStartModelPosition: Position | null = null; @@ -146,9 +152,12 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel } let restorePreviousViewportStart = false; - const conf = this.configuration.editor; + const options = this.configuration.options; + const wrappingInfo = options.get(EditorOption.wrappingInfo); + const fontInfo = options.get(EditorOption.fontInfo); + const wrappingIndent = options.get(EditorOption.wrappingIndent); - if (this.lines.setWrappingSettings(conf.wrappingInfo.wrappingIndent, conf.wrappingInfo.wrappingColumn, conf.fontInfo.typicalFullwidthCharacterWidth / conf.fontInfo.typicalHalfwidthCharacterWidth)) { + if (this.lines.setWrappingSettings(wrappingIndent, wrappingInfo.wrappingColumn, fontInfo.typicalFullwidthCharacterWidth / fontInfo.typicalHalfwidthCharacterWidth)) { eventsCollector.emit(new viewEvents.ViewFlushedEvent()); eventsCollector.emit(new viewEvents.ViewLineMappingChangedEvent()); eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent()); @@ -161,7 +170,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel } } - if (e.readOnly) { + if (e.hasChanged(EditorOption.readOnly)) { // Must read again all decorations due to readOnly filtering this.decorations.reset(); eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent()); @@ -552,7 +561,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel } public getAllOverviewRulerDecorations(theme: ITheme): IOverviewRulerDecorations { - return this.lines.getAllOverviewRulerDecorations(this.editorId, this.configuration.editor.readOnly, theme); + return this.lines.getAllOverviewRulerDecorations(this.editorId, this.configuration.options.get(EditorOption.readOnly), theme); } public invalidateOverviewRulerColorCache(): void { @@ -666,7 +675,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel range = new Range(lineNumber, this.model.getLineMinColumn(lineNumber), lineNumber, this.model.getLineMaxColumn(lineNumber)); } - const fontInfo = this.configuration.editor.fontInfo; + const fontInfo = this.configuration.options.get(EditorOption.fontInfo); const colorMap = this._getColorMap(); const fontFamily = fontInfo.fontFamily === EDITOR_FONT_DEFAULTS.fontFamily ? fontInfo.fontFamily : `'${fontInfo.fontFamily}', ${EDITOR_FONT_DEFAULTS.fontFamily}`; diff --git a/src/vs/editor/contrib/bracketMatching/bracketMatching.ts b/src/vs/editor/contrib/bracketMatching/bracketMatching.ts index 5c778c4e82..92758738b2 100644 --- a/src/vs/editor/contrib/bracketMatching/bracketMatching.ts +++ b/src/vs/editor/contrib/bracketMatching/bracketMatching.ts @@ -22,6 +22,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { registerColor } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant, themeColorFromId } from 'vs/platform/theme/common/themeService'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const overviewRulerBracketMatchForeground = registerColor('editorOverviewRuler.bracketMatchForeground', { dark: '#A0A0A0', light: '#A0A0A0', hc: '#A0A0A0' }, nls.localize('overviewRulerBracketMatchForeground', 'Overview ruler marker color for matching brackets.')); @@ -104,7 +105,7 @@ export class BracketMatchingController extends Disposable implements editorCommo this._lastVersionId = 0; this._decorations = []; this._updateBracketsSoon = this._register(new RunOnceScheduler(() => this._updateBrackets(), 50)); - this._matchBrackets = this._editor.getConfiguration().contribInfo.matchBrackets; + this._matchBrackets = this._editor.getOption(EditorOption.matchBrackets); this._updateBracketsSoon.schedule(); this._register(editor.onDidChangeCursorPosition((e) => { @@ -130,7 +131,7 @@ export class BracketMatchingController extends Disposable implements editorCommo this._updateBracketsSoon.schedule(); })); this._register(editor.onDidChangeConfiguration((e) => { - this._matchBrackets = this._editor.getConfiguration().contribInfo.matchBrackets; + this._matchBrackets = this._editor.getOption(EditorOption.matchBrackets); if (!this._matchBrackets && this._decorations.length > 0) { // Remove existing decorations if bracket matching is off this._decorations = this._editor.deltaDecorations(this._decorations, []); @@ -332,4 +333,4 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { title: nls.localize({ key: 'miGoToBracket', comment: ['&& denotes a mnemonic'] }, "Go to &&Bracket") }, order: 2 -}); \ No newline at end of file +}); diff --git a/src/vs/editor/contrib/clipboard/clipboard.ts b/src/vs/editor/contrib/clipboard/clipboard.ts index b047f1b05e..6ab11c4f69 100644 --- a/src/vs/editor/contrib/clipboard/clipboard.ts +++ b/src/vs/editor/contrib/clipboard/clipboard.ts @@ -16,6 +16,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { MenuId } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const CLIPBOARD_CONTEXT_MENU_GROUP = '9_cutcopypaste'; @@ -94,7 +95,7 @@ class ExecCommandCutAction extends ExecCommandAction { return; } - const emptySelectionClipboard = editor.getConfiguration().emptySelectionClipboard; + const emptySelectionClipboard = editor.getOption(EditorOption.emptySelectionClipboard); if (!emptySelectionClipboard && editor.getSelection().isEmpty()) { return; @@ -143,7 +144,7 @@ class ExecCommandCopyAction extends ExecCommandAction { return; } - const emptySelectionClipboard = editor.getConfiguration().emptySelectionClipboard; + const emptySelectionClipboard = editor.getOption(EditorOption.emptySelectionClipboard); if (!emptySelectionClipboard && editor.getSelection().isEmpty()) { return; @@ -209,7 +210,7 @@ class ExecCommandCopyWithSyntaxHighlightingAction extends ExecCommandAction { return; } - const emptySelectionClipboard = editor.getConfiguration().emptySelectionClipboard; + const emptySelectionClipboard = editor.getOption(EditorOption.emptySelectionClipboard); if (!emptySelectionClipboard && editor.getSelection().isEmpty()) { return; diff --git a/src/vs/editor/contrib/codeAction/codeAction.ts b/src/vs/editor/contrib/codeAction/codeAction.ts index 567667d38d..31c6373e08 100644 --- a/src/vs/editor/contrib/codeAction/codeAction.ts +++ b/src/vs/editor/contrib/codeAction/codeAction.ts @@ -15,7 +15,7 @@ import { CodeAction, CodeActionContext, CodeActionProviderRegistry, CodeActionTr import { IModelService } from 'vs/editor/common/services/modelService'; import { CodeActionFilter, CodeActionKind, CodeActionTrigger, filtersAction, mayIncludeActionsOfKind } from './codeActionTrigger'; import { TextModelCancellationTokenSource } from 'vs/editor/browser/core/editorState'; -import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, IDisposable, Disposable } from 'vs/base/common/lifecycle'; export interface CodeActionSet extends IDisposable { readonly actions: readonly CodeAction[]; @@ -143,6 +143,6 @@ registerLanguageCommand('_executeCodeActionProvider', async function (accessor, { type: 'manual', filter: { includeSourceActions: true, kind: kind && kind.value ? new CodeActionKind(kind.value) : undefined } }, CancellationToken.None); - setTimeout(() => codeActionSet.dispose(), 0); + setTimeout(() => codeActionSet.dispose(), 100); return codeActionSet.actions; }); diff --git a/src/vs/editor/contrib/codeAction/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/codeActionCommands.ts index 5fe9a90798..2fe9d1e7bc 100644 --- a/src/vs/editor/contrib/codeAction/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/codeActionCommands.ts @@ -3,30 +3,32 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { Disposable } from 'vs/base/common/lifecycle'; import { escapeRegExpCharacters } from 'vs/base/common/strings'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, EditorCommand, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; +import { IPosition } from 'vs/editor/common/core/position'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { CodeAction } from 'vs/editor/common/modes'; +import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction'; import { CodeActionUi } from 'vs/editor/contrib/codeAction/codeActionUi'; import { MessageController } from 'vs/editor/contrib/message/messageController'; import * as nls from 'vs/nls'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IMarkerService } from 'vs/platform/markers/common/markers'; +import { INotificationService } from 'vs/platform/notification/common/notification'; import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { CodeActionModel, CodeActionsState, SUPPORTED_CODE_ACTIONS } from './codeActionModel'; import { CodeActionAutoApply, CodeActionFilter, CodeActionKind, CodeActionTrigger } from './codeActionTrigger'; -import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction'; -import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; -import { IPosition } from 'vs/editor/common/core/position'; function contextKeyForSupportedActions(kind: CodeActionKind) { return ContextKeyExpr.regex( @@ -56,6 +58,7 @@ export class QuickFixController extends Disposable implements IEditorContributio @IKeybindingService keybindingService: IKeybindingService, @ICommandService private readonly _commandService: ICommandService, @IBulkEditService private readonly _bulkEditService: IBulkEditService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { super(); @@ -107,21 +110,42 @@ export class QuickFixController extends Disposable implements IEditorContributio } private _applyCodeAction(action: CodeAction): Promise { - return applyCodeAction(action, this._bulkEditService, this._commandService, this._editor); + return this._instantiationService.invokeFunction(applyCodeAction, action, this._bulkEditService, this._commandService, this._editor); } } export async function applyCodeAction( + accessor: ServicesAccessor, action: CodeAction, bulkEditService: IBulkEditService, commandService: ICommandService, editor?: ICodeEditor, ): Promise { + const notificationService = accessor.get(INotificationService); if (action.edit) { await bulkEditService.apply(action.edit, { editor }); } if (action.command) { - await commandService.executeCommand(action.command.id, ...(action.command.arguments || [])); + try { + await commandService.executeCommand(action.command.id, ...(action.command.arguments || [])); + } catch (err) { + const message = asMessage(err); + notificationService.error( + typeof message === 'string' + ? message + : nls.localize('applyCodeActionFailed', "An unknown error occurred while applying the code action")); + + } + } +} + +function asMessage(err: any): string | undefined { + if (typeof err === 'string') { + return err; + } else if (err instanceof Error && typeof err.message === 'string') { + return err.message; + } else { + return undefined; } } diff --git a/src/vs/editor/contrib/codeAction/codeActionModel.ts b/src/vs/editor/contrib/codeAction/codeActionModel.ts index a78b509942..037688bd5e 100644 --- a/src/vs/editor/contrib/codeAction/codeActionModel.ts +++ b/src/vs/editor/contrib/codeAction/codeActionModel.ts @@ -17,6 +17,7 @@ import { IMarkerService } from 'vs/platform/markers/common/markers'; import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { getCodeActions, CodeActionSet } from './codeAction'; import { CodeActionTrigger } from './codeActionTrigger'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export const SUPPORTED_CODE_ACTIONS = new RawContextKey('supportedCodeAction', ''); @@ -192,7 +193,7 @@ export class CodeActionModel extends Disposable { const model = this._editor.getModel(); if (model && CodeActionProviderRegistry.has(model) - && !this._editor.getConfiguration().readOnly + && !this._editor.getOption(EditorOption.readOnly) ) { const supportedActions: string[] = []; for (const provider of CodeActionProviderRegistry.all(model)) { diff --git a/src/vs/editor/contrib/codeAction/lightBulbWidget.ts b/src/vs/editor/contrib/codeAction/lightBulbWidget.ts index d77f32d2e6..ea6979d7c7 100644 --- a/src/vs/editor/contrib/codeAction/lightBulbWidget.ts +++ b/src/vs/editor/contrib/codeAction/lightBulbWidget.ts @@ -14,6 +14,7 @@ import { TextModel } from 'vs/editor/common/model/textModel'; import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction'; import * as nls from 'vs/nls'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; namespace LightBulbState { @@ -78,7 +79,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget { // a bit of extra work to make sure the menu // doesn't cover the line-text const { top, height } = dom.getDomNodePagePosition(this._domNode); - const { lineHeight } = this._editor.getConfiguration(); + const lineHeight = this._editor.getOption(EditorOption.lineHeight); let pad = Math.floor(lineHeight / 3); if (this._state.widgetPosition.position !== null && this._state.widgetPosition.position.lineNumber < this._state.editorPosition.lineNumber) { @@ -106,7 +107,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget { })); this._register(this._editor.onDidChangeConfiguration(e => { // hide when told to do so - if (e.contribInfo && !this._editor.getConfiguration().contribInfo.lightbulbEnabled) { + if (e.hasChanged(EditorOption.lightbulb) && !this._editor.getOption(EditorOption.lightbulb).enabled) { this.hide(); } })); @@ -137,8 +138,8 @@ export class LightBulbWidget extends Disposable implements IContentWidget { return this.hide(); } - const config = this._editor.getConfiguration(); - if (!config.contribInfo.lightbulbEnabled) { + const options = this._editor.getOptions(); + if (!options.get(EditorOption.lightbulb).enabled) { return this.hide(); } @@ -149,9 +150,10 @@ export class LightBulbWidget extends Disposable implements IContentWidget { } const tabSize = model.getOptions().tabSize; + const fontInfo = options.get(EditorOption.fontInfo); const lineContent = model.getLineContent(lineNumber); const indent = TextModel.computeIndentLevel(lineContent, tabSize); - const lineHasSpace = config.fontInfo.spaceWidth * indent > 22; + const lineHasSpace = fontInfo.spaceWidth * indent > 22; const isFolded = (lineNumber: number) => { return lineNumber > 2 && this._editor.getTopForLineNumber(lineNumber) === this._editor.getTopForLineNumber(lineNumber - 1); }; @@ -162,7 +164,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget { effectiveLineNumber -= 1; } else if (!isFolded(lineNumber + 1)) { effectiveLineNumber += 1; - } else if (column * config.fontInfo.spaceWidth < 22) { + } else if (column * fontInfo.spaceWidth < 22) { // cannot show lightbulb above/below and showing // it inline would overlay the cursor... return this.hide(); diff --git a/src/vs/editor/contrib/codelens/codeLensCache.ts b/src/vs/editor/contrib/codelens/codeLensCache.ts index fc32c7d06f..abf40be2fe 100644 --- a/src/vs/editor/contrib/codelens/codeLensCache.ts +++ b/src/vs/editor/contrib/codelens/codeLensCache.ts @@ -17,7 +17,7 @@ import { once } from 'vs/base/common/functional'; export const ICodeLensCache = createDecorator('ICodeLensCache'); export interface ICodeLensCache { - _serviceBrand: any; + _serviceBrand: undefined; put(model: ITextModel, data: CodeLensModel): void; get(model: ITextModel): CodeLensModel | undefined; delete(model: ITextModel): void; @@ -38,7 +38,7 @@ class CacheItem { export class CodeLensCache implements ICodeLensCache { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _fakeProvider = new class implements CodeLensProvider { provideCodeLenses(): CodeLensList { diff --git a/src/vs/editor/contrib/codelens/codelens.ts b/src/vs/editor/contrib/codelens/codelens.ts index 8bb0cdd987..8ad18a40bd 100644 --- a/src/vs/editor/contrib/codelens/codelens.ts +++ b/src/vs/editor/contrib/codelens/codelens.ts @@ -22,14 +22,14 @@ export class CodeLensModel { lenses: CodeLensItem[] = []; - private readonly _dispoables = new DisposableStore(); + private readonly _disposables = new DisposableStore(); dispose(): void { - this._dispoables.dispose(); + this._disposables.dispose(); } add(list: CodeLensList, provider: CodeLensProvider): void { - this._dispoables.add(list); + this._disposables.add(list); for (const symbol of list.lenses) { this.lenses.push({ symbol, provider }); } @@ -89,8 +89,10 @@ registerLanguageCommand('_executeCodeLensProvider', function (accessor, args) { } const result: CodeLens[] = []; + const disposables = new DisposableStore(); return getCodeLensData(model, CancellationToken.None).then(value => { + disposables.add(value); let resolve: Promise[] = []; for (const item of value.lenses) { @@ -101,9 +103,13 @@ registerLanguageCommand('_executeCodeLensProvider', function (accessor, args) { } } - return Promise.all(resolve).finally(() => setTimeout(() => value.dispose(), 0)); + return Promise.all(resolve); }).then(() => { return result; + }).finally(() => { + // make sure to return results, then (on next tick) + // dispose the results + setTimeout(() => disposables.dispose(), 100); }); }); diff --git a/src/vs/editor/contrib/codelens/codelensController.ts b/src/vs/editor/contrib/codelens/codelensController.ts index ed92dc56d0..16ce8b5f46 100644 --- a/src/vs/editor/contrib/codelens/codelensController.ts +++ b/src/vs/editor/contrib/codelens/codelensController.ts @@ -17,6 +17,7 @@ import { CodeLensWidget, CodeLensHelper } from 'vs/editor/contrib/codelens/codel import { ICommandService } from 'vs/platform/commands/common/commands'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ICodeLensCache } from 'vs/editor/contrib/codelens/codeLensCache'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class CodeLensContribution implements editorCommon.IEditorContribution { @@ -40,13 +41,13 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { @INotificationService private readonly _notificationService: INotificationService, @ICodeLensCache private readonly _codeLensCache: ICodeLensCache ) { - this._isEnabled = this._editor.getConfiguration().contribInfo.codeLens; + this._isEnabled = this._editor.getOption(EditorOption.codeLens); this._globalToDispose.add(this._editor.onDidChangeModel(() => this._onModelChange())); this._globalToDispose.add(this._editor.onDidChangeModelLanguage(() => this._onModelChange())); this._globalToDispose.add(this._editor.onDidChangeConfiguration(() => { const prevIsEnabled = this._isEnabled; - this._isEnabled = this._editor.getConfiguration().contribInfo.codeLens; + this._isEnabled = this._editor.getOption(EditorOption.codeLens); if (prevIsEnabled !== this._isEnabled) { this._onModelChange(); } @@ -204,7 +205,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { } })); this._localToDispose.add(this._editor.onDidChangeConfiguration(e => { - if (e.fontInfo) { + if (e.hasChanged(EditorOption.fontInfo)) { for (const lens of this._lenses) { lens.updateHeight(); } diff --git a/src/vs/editor/contrib/codelens/codelensWidget.ts b/src/vs/editor/contrib/codelens/codelensWidget.ts index 6a95fba8fb..a99c7fd82c 100644 --- a/src/vs/editor/contrib/codelens/codelensWidget.ts +++ b/src/vs/editor/contrib/codelens/codelensWidget.ts @@ -16,6 +16,7 @@ import { editorCodeLensForeground } from 'vs/editor/common/view/editorColorRegis import { CodeLensItem } from 'vs/editor/contrib/codelens/codelens'; import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; class CodeLensViewZone implements editorBrowser.IViewZone { @@ -80,7 +81,9 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { } updateHeight(): void { - const { fontInfo, lineHeight } = this._editor.getConfiguration(); + const options = this._editor.getOptions(); + const fontInfo = options.get(EditorOption.fontInfo); + const lineHeight = options.get(EditorOption.lineHeight); this._domNode.style.height = `${Math.round(lineHeight * 1.1)}px`; this._domNode.style.lineHeight = `${lineHeight}px`; this._domNode.style.fontSize = `${Math.round(fontInfo.fontSize * 0.9)}px`; diff --git a/src/vs/editor/contrib/colorPicker/colorDetector.ts b/src/vs/editor/contrib/colorPicker/colorDetector.ts index b34ed1b937..a1d7685a0d 100644 --- a/src/vs/editor/contrib/colorPicker/colorDetector.ts +++ b/src/vs/editor/contrib/colorPicker/colorDetector.ts @@ -19,6 +19,7 @@ import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { ColorProviderRegistry } from 'vs/editor/common/modes'; import { IColorData, getColors } from 'vs/editor/contrib/colorPicker/color'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const MAX_DECORATORS = 500; @@ -84,7 +85,7 @@ export class ColorDetector extends Disposable implements IEditorContribution { } } - return this._editor.getConfiguration().contribInfo.colorDecorators; + return this._editor.getOption(EditorOption.colorDecorators); } getId(): string { diff --git a/src/vs/editor/contrib/contextmenu/contextmenu.ts b/src/vs/editor/contrib/contextmenu/contextmenu.ts index 74f55dd764..e03c476c39 100644 --- a/src/vs/editor/contrib/contextmenu/contextmenu.ts +++ b/src/vs/editor/contrib/contextmenu/contextmenu.ts @@ -22,6 +22,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ITextModel } from 'vs/editor/common/model'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class ContextMenuController implements IEditorContribution { @@ -66,7 +67,7 @@ export class ContextMenuController implements IEditorContribution { return; } - if (!this._editor.getConfiguration().contribInfo.contextmenu) { + if (!this._editor.getOption(EditorOption.contextmenu)) { this._editor.focus(); // Ensure the cursor is at the position of the mouse click if (e.target.position && !this._editor.getSelection().containsPosition(e.target.position)) { @@ -104,7 +105,7 @@ export class ContextMenuController implements IEditorContribution { } public showContextMenu(anchor?: IAnchor | null): void { - if (!this._editor.getConfiguration().contribInfo.contextmenu) { + if (!this._editor.getOption(EditorOption.contextmenu)) { return; // Context menu is turned off through configuration } if (!this._editor.hasModel()) { @@ -147,7 +148,7 @@ export class ContextMenuController implements IEditorContribution { } // Disable hover - const oldHoverSetting = this._editor.getConfiguration().contribInfo.hover; + const oldHoverSetting = this._editor.getOption(EditorOption.hover); this._editor.updateOptions({ hover: { enabled: false diff --git a/src/vs/editor/contrib/dnd/dnd.ts b/src/vs/editor/contrib/dnd/dnd.ts index bb50bac3b8..433b7d0b31 100644 --- a/src/vs/editor/contrib/dnd/dnd.ts +++ b/src/vs/editor/contrib/dnd/dnd.ts @@ -19,6 +19,7 @@ import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { IModelDeltaDecoration } from 'vs/editor/common/model'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; function hasTriggerModifier(e: IKeyboardEvent | IMouseEvent): boolean { if (isMacintosh) { @@ -67,7 +68,7 @@ export class DragAndDropController extends Disposable implements editorCommon.IE } private onEditorKeyDown(e: IKeyboardEvent): void { - if (!this._editor.getConfiguration().dragAndDrop) { + if (!this._editor.getOption(EditorOption.dragAndDrop)) { return; } @@ -83,7 +84,7 @@ export class DragAndDropController extends Disposable implements editorCommon.IE } private onEditorKeyUp(e: IKeyboardEvent): void { - if (!this._editor.getConfiguration().dragAndDrop) { + if (!this._editor.getOption(EditorOption.dragAndDrop)) { return; } diff --git a/src/vs/editor/contrib/documentSymbols/outlineModel.ts b/src/vs/editor/contrib/documentSymbols/outlineModel.ts index 9f489d9398..fce2c9378a 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineModel.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineModel.ts @@ -386,6 +386,9 @@ export class OutlineModel extends TreeElement { protected constructor(readonly textModel: ITextModel) { super(); + + this.id = 'root'; + this.parent = undefined; } adopt(): OutlineModel { diff --git a/src/vs/editor/contrib/find/findController.ts b/src/vs/editor/contrib/find/findController.ts index 5cb0132ad3..f95774acb6 100644 --- a/src/vs/editor/contrib/find/findController.ts +++ b/src/vs/editor/contrib/find/findController.ts @@ -26,6 +26,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { INotificationService } from 'vs/platform/notification/common/notification'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const SEARCH_STRING_MAX_LENGTH = 524288; @@ -120,7 +121,7 @@ export class CommonFindController extends Disposable implements editorCommon.IEd if (shouldRestartFind) { this._start({ forceRevealReplace: false, - seedSearchStringFromSelection: false && this._editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection, + seedSearchStringFromSelection: false && this._editor.getOption(EditorOption.find).seedSearchStringFromSelection, seedSearchStringFromGlobalClipboard: false, shouldFocus: FindStartFocusAction.NoFocusChange, shouldAnimate: false, @@ -352,7 +353,7 @@ export class CommonFindController extends Disposable implements editorCommon.IEd } public getGlobalBufferTerm(): string { - if (this._editor.getConfiguration().contribInfo.find.globalFindClipboard + if (this._editor.getOption(EditorOption.find).globalFindClipboard && this._clipboardService && this._editor.hasModel() && !this._editor.getModel().isTooLargeForSyncing() @@ -363,7 +364,7 @@ export class CommonFindController extends Disposable implements editorCommon.IEd } public setGlobalBufferTerm(text: string) { - if (this._editor.getConfiguration().contribInfo.find.globalFindClipboard + if (this._editor.getOption(EditorOption.find).globalFindClipboard && this._clipboardService && this._editor.hasModel() && !this._editor.getModel().isTooLargeForSyncing() @@ -398,7 +399,7 @@ export class FindController extends CommonFindController implements IFindControl this._createFindWidget(); } - if (!this._widget!.getPosition() && this._editor.getConfiguration().contribInfo.find.autoFindInSelection) { + if (!this._widget!.getPosition() && this._editor.getOption(EditorOption.find).autoFindInSelection) { // not visible yet so we need to set search scope if `editor.find.autoFindInSelection` is `true` opts.updateSearchScope = true; } @@ -456,8 +457,8 @@ export class StartFindAction extends EditorAction { if (controller) { controller.start({ forceRevealReplace: false, - seedSearchStringFromSelection: editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection, - seedSearchStringFromGlobalClipboard: editor.getConfiguration().contribInfo.find.globalFindClipboard, + seedSearchStringFromSelection: editor.getOption(EditorOption.find).seedSearchStringFromSelection, + seedSearchStringFromGlobalClipboard: editor.getOption(EditorOption.find).globalFindClipboard, shouldFocus: FindStartFocusAction.FocusFindInput, shouldAnimate: true, updateSearchScope: false @@ -507,7 +508,7 @@ export abstract class MatchFindAction extends EditorAction { if (controller && !this._run(controller)) { controller.start({ forceRevealReplace: false, - seedSearchStringFromSelection: (controller.getState().searchString.length === 0) && editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection, + seedSearchStringFromSelection: (controller.getState().searchString.length === 0) && editor.getOption(EditorOption.find).seedSearchStringFromSelection, seedSearchStringFromGlobalClipboard: true, shouldFocus: FindStartFocusAction.NoFocusChange, shouldAnimate: true, @@ -619,7 +620,7 @@ export abstract class SelectionMatchFindAction extends EditorAction { if (!this._run(controller)) { controller.start({ forceRevealReplace: false, - seedSearchStringFromSelection: editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection, + seedSearchStringFromSelection: editor.getOption(EditorOption.find).seedSearchStringFromSelection, seedSearchStringFromGlobalClipboard: false, shouldFocus: FindStartFocusAction.NoFocusChange, shouldAnimate: true, @@ -698,7 +699,7 @@ export class StartFindReplaceAction extends EditorAction { } public run(accessor: ServicesAccessor | null, editor: ICodeEditor): void { - if (!editor.hasModel() || editor.getConfiguration().readOnly) { + if (!editor.hasModel() || editor.getOption(EditorOption.readOnly)) { return; } @@ -708,7 +709,7 @@ export class StartFindReplaceAction extends EditorAction { // we only seed search string from selection when the current selection is single line and not empty, // + the find input is not focused let seedSearchStringFromSelection = !currentSelection.isEmpty() - && currentSelection.startLineNumber === currentSelection.endLineNumber && editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection + && currentSelection.startLineNumber === currentSelection.endLineNumber && editor.getOption(EditorOption.find).seedSearchStringFromSelection && !findInputFocused; /* * if the existing search string in find widget is empty and we don't seed search string from selection, it means the Find Input is still empty, so we should focus the Find Input instead of Replace Input. @@ -725,7 +726,7 @@ export class StartFindReplaceAction extends EditorAction { controller.start({ forceRevealReplace: true, seedSearchStringFromSelection: seedSearchStringFromSelection, - seedSearchStringFromGlobalClipboard: editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection, + seedSearchStringFromGlobalClipboard: editor.getOption(EditorOption.find).seedSearchStringFromSelection, shouldFocus: shouldFocus, shouldAnimate: true, updateSearchScope: false diff --git a/src/vs/editor/contrib/find/findModel.ts b/src/vs/editor/contrib/find/findModel.ts index 000e655abb..49a181ab87 100644 --- a/src/vs/editor/contrib/find/findModel.ts +++ b/src/vs/editor/contrib/find/findModel.ts @@ -22,6 +22,7 @@ import { ReplaceAllCommand } from 'vs/editor/contrib/find/replaceAllCommand'; import { ReplacePattern, parseReplaceString } from 'vs/editor/contrib/find/replacePattern'; import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export const CONTEXT_FIND_WIDGET_VISIBLE = new RawContextKey('findWidgetVisible', false); export const CONTEXT_FIND_WIDGET_NOT_VISIBLE: ContextKeyExpr = CONTEXT_FIND_WIDGET_VISIBLE.toNegated(); @@ -287,12 +288,12 @@ export class FindModelBoundToEditorModel { let position = new Position(lineNumber, column); - let prevMatch = model.findPreviousMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false); + let prevMatch = model.findPreviousMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false); if (prevMatch && prevMatch.range.isEmpty() && prevMatch.range.getStartPosition().equals(position)) { // Looks like we're stuck at this position, unacceptable! position = this._prevSearchPosition(position); - prevMatch = model.findPreviousMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false); + prevMatch = model.findPreviousMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false); } if (!prevMatch) { @@ -379,12 +380,12 @@ export class FindModelBoundToEditorModel { let position = new Position(lineNumber, column); - let nextMatch = model.findNextMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getConfiguration().wordSeparators : null, captureMatches); + let nextMatch = model.findNextMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, captureMatches); if (forceMove && nextMatch && nextMatch.range.isEmpty() && nextMatch.range.getStartPosition().equals(position)) { // Looks like we're stuck at this position, unacceptable! position = this._nextSearchPosition(position); - nextMatch = model.findNextMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getConfiguration().wordSeparators : null, captureMatches); + nextMatch = model.findNextMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, captureMatches); } if (!nextMatch) { @@ -438,7 +439,7 @@ export class FindModelBoundToEditorModel { private _findMatches(findScope: Range | null, captureMatches: boolean, limitResultCount: number): FindMatch[] { let searchRange = FindModelBoundToEditorModel._getSearchRange(this._editor.getModel(), findScope); - return this._editor.getModel().findMatches(this._state.searchString, searchRange, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getConfiguration().wordSeparators : null, captureMatches, limitResultCount); + return this._editor.getModel().findMatches(this._state.searchString, searchRange, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, captureMatches, limitResultCount); } public replaceAll(): void { @@ -459,7 +460,7 @@ export class FindModelBoundToEditorModel { } private _largeReplaceAll(): void { - const searchParams = new SearchParams(this._state.searchString, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getConfiguration().wordSeparators : null); + const searchParams = new SearchParams(this._state.searchString, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null); const searchData = searchParams.parseSearchRequest(); if (!searchData) { return; @@ -467,7 +468,7 @@ export class FindModelBoundToEditorModel { let searchRegex = searchData.regex; if (!searchRegex.multiline) { - let mod = 'm'; + let mod = 'mu'; if (searchRegex.ignoreCase) { mod += 'i'; } diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts index 54161f62b9..a6b76b13d6 100644 --- a/src/vs/editor/contrib/find/findWidget.ts +++ b/src/vs/editor/contrib/find/findWidget.ts @@ -23,7 +23,7 @@ import { toDisposable } from 'vs/base/common/lifecycle'; import * as platform from 'vs/base/common/platform'; import * as strings from 'vs/base/common/strings'; import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, IViewZone, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Range } from 'vs/editor/common/core/range'; import { CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_REPLACE_INPUT_FOCUSED, FIND_IDS, MATCHES_LIMIT } from 'vs/editor/contrib/find/findModel'; import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState'; @@ -67,6 +67,7 @@ let FIND_ALL_CONTROLS_WIDTH = 17/** Find Input margin-left */ + (MAX_MATCHES_COU const FIND_INPUT_AREA_HEIGHT = 33; // The height of Find Widget when Replace Input is not visible. const ctrlEnterReplaceAllWarningPromptedKey = 'ctrlEnterReplaceAll.windows.donotask'; +const ctrlKeyMod = (platform.isMacintosh ? KeyMod.WinCtrl : KeyMod.CtrlCmd); export class FindWidgetViewZone implements IViewZone { public readonly afterLineNumber: number; public heightInPx: number; @@ -111,7 +112,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas private readonly _notificationService: INotificationService; private _domNode!: HTMLElement; - private _cachedHeight: number | null; + private _cachedHeight: number | null = null; private _findInput!: FindInput; private _replaceInput!: ReplaceInput; @@ -175,24 +176,24 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas this._tryUpdateWidgetWidth(); this._findInput.inputBox.layout(); - this._register(this._codeEditor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - if (e.readOnly) { - if (this._codeEditor.getConfiguration().readOnly) { + this._register(this._codeEditor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.readOnly)) { + if (this._codeEditor.getOption(EditorOption.readOnly)) { // Hide replace part if editor becomes read only this._state.change({ isReplaceRevealed: false }, false); } this._updateButtons(); } - if (e.layoutInfo) { + if (e.hasChanged(EditorOption.layoutInfo)) { this._tryUpdateWidgetWidth(); } - if (e.accessibilitySupport) { + if (e.hasChanged(EditorOption.accessibilitySupport)) { this.updateAccessibilitySupport(); } - if (e.contribInfo) { - const addExtraSpaceOnTop = this._codeEditor.getConfiguration().contribInfo.find.addExtraSpaceOnTop; + if (e.hasChanged(EditorOption.find)) { + const addExtraSpaceOnTop = this._codeEditor.getOption(EditorOption.find).addExtraSpaceOnTop; if (addExtraSpaceOnTop && !this._viewZone) { this._viewZone = new FindWidgetViewZone(0); this._showViewZone(); @@ -238,7 +239,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas })); this._codeEditor.addOverlayWidget(this); - if (this._codeEditor.getConfiguration().contribInfo.find.addExtraSpaceOnTop) { + if (this._codeEditor.getOption(EditorOption.find).addExtraSpaceOnTop) { this._viewZone = new FindWidgetViewZone(0); // Put it before the first line then users can scroll beyond the first line. } @@ -315,7 +316,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } if (e.isReplaceRevealed) { if (this._state.isReplaceRevealed) { - if (!this._codeEditor.getConfiguration().readOnly && !this._isReplaceVisible) { + if (!this._codeEditor.getOption(EditorOption.readOnly) && !this._isReplaceVisible) { this._isReplaceVisible = true; this._replaceInput.width = dom.getTotalWidth(this._findInput.domNode); this._updateButtons(); @@ -456,7 +457,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas this._toggleReplaceBtn.toggleClass('expand', this._isReplaceVisible); this._toggleReplaceBtn.setExpanded(this._isReplaceVisible); - let canReplace = !this._codeEditor.getConfiguration().readOnly; + let canReplace = !this._codeEditor.getOption(EditorOption.readOnly); this._toggleReplaceBtn.setEnabled(this._isVisible && canReplace); } @@ -466,7 +467,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas const selection = this._codeEditor.getSelection(); const isSelection = selection ? (selection.startLineNumber !== selection.endLineNumber || selection.startColumn !== selection.endColumn) : false; - if (isSelection && this._codeEditor.getConfiguration().contribInfo.find.autoFindInSelection) { + if (isSelection && this._codeEditor.getOption(EditorOption.find).autoFindInSelection) { this._toggleSelectionFind.checked = true; } else { this._toggleSelectionFind.checked = false; @@ -487,7 +488,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas this._codeEditor.layoutOverlayWidget(this); let adjustEditorScrollTop = true; - if (this._codeEditor.getConfiguration().contribInfo.find.seedSearchStringFromSelection && selection) { + if (this._codeEditor.getOption(EditorOption.find).seedSearchStringFromSelection && selection) { const domNode = this._codeEditor.getDomNode(); if (domNode) { const editorCoords = dom.getDomNodePagePosition(domNode); @@ -534,7 +535,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } private _layoutViewZone() { - const addExtraSpaceOnTop = this._codeEditor.getConfiguration().contribInfo.find.addExtraSpaceOnTop; + const addExtraSpaceOnTop = this._codeEditor.getOption(EditorOption.find).addExtraSpaceOnTop; if (!addExtraSpaceOnTop) { this._removeViewZone(); @@ -562,7 +563,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas return; } - const addExtraSpaceOnTop = this._codeEditor.getConfiguration().contribInfo.find.addExtraSpaceOnTop; + const addExtraSpaceOnTop = this._codeEditor.getOption(EditorOption.find).addExtraSpaceOnTop; if (!addExtraSpaceOnTop) { return; @@ -642,7 +643,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas return; } - const editorContentWidth = this._codeEditor.getConfiguration().layoutInfo.contentWidth; + const layoutInfo = this._codeEditor.getLayoutInfo(); + const editorContentWidth = layoutInfo.contentWidth; if (editorContentWidth <= 0) { // for example, diff view original editor @@ -652,8 +654,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas dom.removeClass(this._domNode, 'hiddenEditor'); } - const editorWidth = this._codeEditor.getConfiguration().layoutInfo.width; - const minimapWidth = this._codeEditor.getConfiguration().layoutInfo.minimapWidth; + const editorWidth = layoutInfo.width; + const minimapWidth = layoutInfo.minimapWidth; let collapsedFindWidget = false; let reducedFindWidget = false; let narrowFindWidget = false; @@ -775,20 +777,10 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } private _onFindInputKeyDown(e: IKeyboardEvent): void { - if (e.equals(KeyMod.WinCtrl | KeyCode.Enter)) { - const inputElement = this._findInput.inputBox.inputElement; - const start = inputElement.selectionStart; - const end = inputElement.selectionEnd; - const content = inputElement.value; - - if (start && end) { - const value = content.substr(0, start) + '\n' + content.substr(end); - this._findInput.inputBox.value = value; - inputElement.setSelectionRange(start + 1, start + 1); - this._findInput.inputBox.layout(); - e.preventDefault(); - return; - } + if (e.equals(ctrlKeyMod | KeyCode.Enter)) { + this._findInput.inputBox.insertAtCursor('\n'); + e.preventDefault(); + return; } if (e.equals(KeyCode.Tab)) { @@ -817,7 +809,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } private _onReplaceInputKeyDown(e: IKeyboardEvent): void { - if (e.equals(KeyMod.WinCtrl | KeyCode.Enter)) { + if (e.equals(ctrlKeyMod | KeyCode.Enter)) { if (platform.isWindows && platform.isNative && !this._ctrlEnterReplaceAllWarningPrompted) { // this is the first time when users press Ctrl + Enter to replace all this._notificationService.info( @@ -830,19 +822,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } - const inputElement = this._replaceInput.inputBox.inputElement; - const start = inputElement.selectionStart; - const end = inputElement.selectionEnd; - const content = inputElement.value; - - if (start && end) { - const value = content.substr(0, start) + '\n' + content.substr(end); - this._replaceInput.inputBox.value = value; - inputElement.setSelectionRange(start + 1, start + 1); - this._replaceInput.inputBox.layout(); - e.preventDefault(); - return; - } + this._replaceInput.inputBox.insertAtCursor('\n'); + e.preventDefault(); + return; } if (e.equals(KeyCode.Tab)) { @@ -1187,7 +1169,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas if (!this._resized || currentWidth === FIND_WIDGET_INITIAL_WIDTH) { // 1. never resized before, double click should maximizes it // 2. users resized it already but its width is the same as default - width = this._codeEditor.getConfiguration().layoutInfo.width - 28 - this._codeEditor.getConfiguration().layoutInfo.minimapWidth - 15; + const layoutInfo = this._codeEditor.getLayoutInfo(); + width = layoutInfo.width - 28 - layoutInfo.minimapWidth - 15; this._resized = true; } else { /** @@ -1208,7 +1191,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } private updateAccessibilitySupport(): void { - const value = this._codeEditor.getConfiguration().accessibilitySupport; + const value = this._codeEditor.getOption(EditorOption.accessibilitySupport); this._findInput.setFocusInputOnOptionClick(value !== AccessibilitySupport.Enabled); } } diff --git a/src/vs/editor/contrib/find/test/replacePattern.test.ts b/src/vs/editor/contrib/find/test/replacePattern.test.ts index 9ff703c4a4..23e4ab13b3 100644 --- a/src/vs/editor/contrib/find/test/replacePattern.test.ts +++ b/src/vs/editor/contrib/find/test/replacePattern.test.ts @@ -183,6 +183,15 @@ suite('Replace Pattern test', () => { assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo-newbar-newabc'), 'Newfoo-Newbar-Newabc'); actual = ['Foo-Bar-abc']; assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo-newbar'), 'Newfoo-newbar'); + + actual = ['Foo_Bar']; + assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo_newbar'), 'Newfoo_Newbar'); + actual = ['Foo_Bar_Abc']; + assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo_newbar_newabc'), 'Newfoo_Newbar_Newabc'); + actual = ['Foo_Bar_abc']; + assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo_newbar'), 'Newfoo_newbar'); + actual = ['Foo_Bar-abc']; + assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo_newbar-abc'), 'Newfoo_newbar-abc'); }); test('preserve case', () => { @@ -217,5 +226,21 @@ suite('Replace Pattern test', () => { replacePattern = parseReplaceString('newfoo-newbar'); actual = replacePattern.buildReplaceString(['Foo-Bar-abc'], true); assert.equal(actual, 'Newfoo-newbar'); + + replacePattern = parseReplaceString('newfoo_newbar'); + actual = replacePattern.buildReplaceString(['Foo_Bar'], true); + assert.equal(actual, 'Newfoo_Newbar'); + + replacePattern = parseReplaceString('newfoo_newbar_newabc'); + actual = replacePattern.buildReplaceString(['Foo_Bar_Abc'], true); + assert.equal(actual, 'Newfoo_Newbar_Newabc'); + + replacePattern = parseReplaceString('newfoo_newbar'); + actual = replacePattern.buildReplaceString(['Foo_Bar_abc'], true); + assert.equal(actual, 'Newfoo_newbar'); + + replacePattern = parseReplaceString('newfoo_newbar-abc'); + actual = replacePattern.buildReplaceString(['Foo_Bar-abc'], true); + assert.equal(actual, 'Newfoo_newbar-abc'); }); }); diff --git a/src/vs/editor/contrib/folding/folding.ts b/src/vs/editor/contrib/folding/folding.ts index 1961ef18ae..3cc0150c1d 100644 --- a/src/vs/editor/contrib/folding/folding.ts +++ b/src/vs/editor/contrib/folding/folding.ts @@ -18,7 +18,7 @@ import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStat import { FoldingDecorationProvider } from './foldingDecorations'; import { FoldingRegions, FoldingRegion } from './foldingRanges'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IMarginData, IEmptyContentData } from 'vs/editor/browser/controller/mouseTarget'; import { HiddenRangeModel } from 'vs/editor/contrib/folding/hiddenRangeModel'; import { IRange } from 'vs/editor/common/core/range'; @@ -87,9 +87,10 @@ export class FoldingController extends Disposable implements IEditorContribution ) { super(); this.editor = editor; - this._isEnabled = this.editor.getConfiguration().contribInfo.folding; - this._autoHideFoldingControls = this.editor.getConfiguration().contribInfo.showFoldingControls === 'mouseover'; - this._useFoldingProviders = this.editor.getConfiguration().contribInfo.foldingStrategy !== 'indentation'; + const options = this.editor.getOptions(); + this._isEnabled = options.get(EditorOption.folding); + this._autoHideFoldingControls = options.get(EditorOption.showFoldingControls) === 'mouseover'; + this._useFoldingProviders = options.get(EditorOption.foldingStrategy) !== 'indentation'; this.foldingModel = null; this.hiddenRangeModel = null; @@ -108,22 +109,23 @@ export class FoldingController extends Disposable implements IEditorContribution this._register(this.editor.onDidChangeModel(() => this.onModelChanged())); - this._register(this.editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - if (e.contribInfo) { + this._register(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.folding) || e.hasChanged(EditorOption.showFoldingControls) || e.hasChanged(EditorOption.foldingStrategy)) { let oldIsEnabled = this._isEnabled; - this._isEnabled = this.editor.getConfiguration().contribInfo.folding; + const options = this.editor.getOptions(); + this._isEnabled = options.get(EditorOption.folding); this.foldingEnabled.set(this._isEnabled); if (oldIsEnabled !== this._isEnabled) { this.onModelChanged(); } let oldShowFoldingControls = this._autoHideFoldingControls; - this._autoHideFoldingControls = this.editor.getConfiguration().contribInfo.showFoldingControls === 'mouseover'; + this._autoHideFoldingControls = options.get(EditorOption.showFoldingControls) === 'mouseover'; if (oldShowFoldingControls !== this._autoHideFoldingControls) { this.foldingDecorationProvider.autoHideFoldingControls = this._autoHideFoldingControls; this.onModelContentChanged(); } let oldUseFoldingProviders = this._useFoldingProviders; - this._useFoldingProviders = this.editor.getConfiguration().contribInfo.foldingStrategy !== 'indentation'; + this._useFoldingProviders = options.get(EditorOption.foldingStrategy) !== 'indentation'; if (oldUseFoldingProviders !== this._useFoldingProviders) { this.onFoldingStrategyChanged(); } diff --git a/src/vs/editor/contrib/format/formatActions.ts b/src/vs/editor/contrib/format/formatActions.ts index 27787975d4..85ec4760d7 100644 --- a/src/vs/editor/contrib/format/formatActions.ts +++ b/src/vs/editor/contrib/format/formatActions.ts @@ -24,6 +24,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; class FormatOnType implements editorCommon.IEditorContribution { @@ -59,7 +60,7 @@ class FormatOnType implements editorCommon.IEditorContribution { this._callOnModel.clear(); // we are disabled - if (!this._editor.getConfiguration().contribInfo.formatOnType) { + if (!this._editor.getOption(EditorOption.formatOnType)) { return; } @@ -184,7 +185,7 @@ class FormatOnPaste implements editorCommon.IEditorContribution { this._callOnModel.clear(); // we are disabled - if (!this.editor.getConfiguration().contribInfo.formatOnPaste) { + if (!this.editor.getOption(EditorOption.formatOnPaste)) { return; } diff --git a/src/vs/editor/contrib/goToDefinition/clickLinkGesture.ts b/src/vs/editor/contrib/goToDefinition/clickLinkGesture.ts index 03918881e8..c6c55e1bb5 100644 --- a/src/vs/editor/contrib/goToDefinition/clickLinkGesture.ts +++ b/src/vs/editor/contrib/goToDefinition/clickLinkGesture.ts @@ -12,6 +12,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { Event, Emitter } from 'vs/base/common/event'; import * as platform from 'vs/base/common/platform'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; function hasModifier(e: { ctrlKey: boolean; shiftKey: boolean; altKey: boolean; metaKey: boolean }, modifier: 'ctrlKey' | 'shiftKey' | 'altKey' | 'metaKey'): boolean { return !!e[modifier]; @@ -116,14 +117,14 @@ export class ClickLinkGesture extends Disposable { super(); this._editor = editor; - this._opts = createOptions(this._editor.getConfiguration().multiCursorModifier); + this._opts = createOptions(this._editor.getOption(EditorOption.multiCursorModifier)); this.lastMouseMoveEvent = null; this.hasTriggerKeyOnMouseDown = false; this._register(this._editor.onDidChangeConfiguration((e) => { - if (e.multiCursorModifier) { - const newOpts = createOptions(this._editor.getConfiguration().multiCursorModifier); + if (e.hasChanged(EditorOption.multiCursorModifier)) { + const newOpts = createOptions(this._editor.getOption(EditorOption.multiCursorModifier)); if (this._opts.equals(newOpts)) { return; } diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts index 3ea69fc591..8b52db0fc3 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts @@ -30,6 +30,7 @@ import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefiniti import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { EditorStateCancellationTokenSource, CodeEditorStateFlag } from 'vs/editor/browser/core/editorState'; import { ISymbolNavigationService } from 'vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class DefinitionActionConfig { @@ -137,7 +138,7 @@ export class DefinitionAction extends EditorAction { const msg = model.getAriaMessage(); alert(msg); - const { gotoLocation } = editor.getConfiguration().contribInfo; + const gotoLocation = editor.getOption(EditorOption.gotoLocation); if (this._configuration.openInPeek || (gotoLocation.multiple === 'peek' && model.references.length > 1)) { this._openInPeek(editorService, editor, model); diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts index ef5057bd51..09e5065aa6 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts @@ -24,7 +24,7 @@ export const ctxHasSymbols = new RawContextKey('hasSymbols', false); export const ISymbolNavigationService = createDecorator('ISymbolNavigationService'); export interface ISymbolNavigationService { - _serviceBrand: any; + _serviceBrand: undefined; reset(): void; put(anchor: OneReference): void; revealNext(source: ICodeEditor): Promise; @@ -32,7 +32,7 @@ export interface ISymbolNavigationService { class SymbolNavigationService implements ISymbolNavigationService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _ctxHasSymbols: IContextKey; diff --git a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts index 0dde37e8e2..f07e0c52ce 100644 --- a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts +++ b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/gotoErrorWidget'; import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; -import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, DisposableStore } from 'vs/base/common/lifecycle'; import { IMarker, MarkerSeverity, IRelatedInformation } from 'vs/platform/markers/common/markers'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; @@ -26,6 +26,7 @@ import { IAction } from 'vs/base/common/actions'; import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/referenceSearch/referencesWidget'; import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; class MessageWidget { @@ -37,7 +38,7 @@ class MessageWidget { private readonly _relatedBlock: HTMLDivElement; private readonly _scrollable: ScrollableElement; private readonly _relatedDiagnostics = new WeakMap(); - private readonly _disposables: IDisposable[] = []; + private readonly _disposables: DisposableStore = new DisposableStore(); constructor(parent: HTMLElement, editor: ICodeEditor, onRelatedInformation: (related: IRelatedInformation) => void) { this._editor = editor; @@ -53,7 +54,7 @@ class MessageWidget { this._relatedBlock = document.createElement('div'); domNode.appendChild(this._relatedBlock); - this._disposables.push(dom.addStandardDisposableListener(this._relatedBlock, 'click', event => { + this._disposables.add(dom.addStandardDisposableListener(this._relatedBlock, 'click', event => { event.preventDefault(); const related = this._relatedDiagnostics.get(event.target); if (related) { @@ -69,11 +70,11 @@ class MessageWidget { verticalScrollbarSize: 3 }); parent.appendChild(this._scrollable.getDomNode()); - this._disposables.push(this._scrollable.onScroll(e => { + this._disposables.add(this._scrollable.onScroll(e => { domNode.style.left = `-${e.scrollLeft}px`; domNode.style.top = `-${e.scrollTop}px`; })); - this._disposables.push(this._scrollable); + this._disposables.add(this._scrollable); } dispose(): void { @@ -122,7 +123,7 @@ class MessageWidget { this._editor.applyFontInfo(this._relatedBlock); if (isNonEmptyArray(relatedInformation)) { const relatedInformationNode = this._relatedBlock.appendChild(document.createElement('div')); - relatedInformationNode.style.paddingTop = `${Math.floor(this._editor.getConfiguration().lineHeight * 0.66)}px`; + relatedInformationNode.style.paddingTop = `${Math.floor(this._editor.getOption(EditorOption.lineHeight) * 0.66)}px`; this._lines += 1; for (const related of relatedInformation) { @@ -146,7 +147,7 @@ class MessageWidget { } } - const fontInfo = this._editor.getConfiguration().fontInfo; + const fontInfo = this._editor.getOption(EditorOption.fontInfo); const scrollWidth = Math.ceil(fontInfo.typicalFullwidthCharacterWidth * this._longestLineLength * 0.75); const scrollHeight = fontInfo.lineHeight * this._lines; this._scrollable.setScrollDimensions({ scrollWidth, scrollHeight }); diff --git a/src/vs/editor/contrib/hover/hover.css b/src/vs/editor/contrib/hover/hover.css index 26daad5c4e..26f1531a19 100644 --- a/src/vs/editor/contrib/hover/hover.css +++ b/src/vs/editor/contrib/hover/hover.css @@ -55,9 +55,13 @@ margin-bottom: 0; } +/* MarkupContent Layout */ .monaco-editor-hover ul { padding-left: 20px; } +.monaco-editor-hover ol { + padding-left: 20px; +} .monaco-editor-hover li > p { margin-bottom: 0; diff --git a/src/vs/editor/contrib/hover/hover.ts b/src/vs/editor/contrib/hover/hover.ts index b553c9e551..f0d49d3764 100644 --- a/src/vs/editor/contrib/hover/hover.ts +++ b/src/vs/editor/contrib/hover/hover.ts @@ -11,7 +11,7 @@ import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IEmptyContentData } from 'vs/editor/browser/controller/mouseTarget'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Range } from 'vs/editor/common/core/range'; import { IEditorContribution, IScrollEvent } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; @@ -74,8 +74,8 @@ export class ModesHoverController implements IEditorContribution { this._hookEvents(); - this._didChangeConfigurationHandler = this._editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - if (e.contribInfo) { + this._didChangeConfigurationHandler = this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.hover)) { this._hideWidgets(); this._unhookEvents(); this._hookEvents(); @@ -86,7 +86,7 @@ export class ModesHoverController implements IEditorContribution { private _hookEvents(): void { const hideWidgetsEventHandler = () => this._hideWidgets(); - const hoverOpts = this._editor.getConfiguration().contribInfo.hover; + const hoverOpts = this._editor.getOption(EditorOption.hover); this._isHoverEnabled = hoverOpts.enabled; this._isHoverSticky = hoverOpts.sticky; if (this._isHoverEnabled) { @@ -147,7 +147,6 @@ export class ModesHoverController implements IEditorContribution { } private _onEditorMouseMove(mouseEvent: IEditorMouseEvent): void { - // const this._editor.getConfiguration().contribInfo.hover.sticky; let targetType = mouseEvent.target.type; if (this._isMouseDown && this._hoverClicked && this.contentWidget.isColorPickerVisible()) { @@ -165,7 +164,7 @@ export class ModesHoverController implements IEditorContribution { } if (targetType === MouseTargetType.CONTENT_EMPTY) { - const epsilon = this._editor.getConfiguration().fontInfo.typicalHalfwidthCharacterWidth / 2; + const epsilon = this._editor.getOption(EditorOption.fontInfo).typicalHalfwidthCharacterWidth / 2; const data = mouseEvent.target.detail; if (data && !data.isAfterLines && typeof data.horizontalDistanceToText === 'number' && data.horizontalDistanceToText < epsilon) { // Let hover kick in even when the mouse is technically in the empty area after a line, given the distance is small enough @@ -265,7 +264,7 @@ class ShowHoverAction extends EditorAction { } const position = editor.getPosition(); const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column); - const focus = editor.getConfiguration().accessibilitySupport === AccessibilitySupport.Enabled; + const focus = editor.getOption(EditorOption.accessibilitySupport) === AccessibilitySupport.Enabled; controller.showContentHover(range, HoverStartMode.Immediate, focus); } } diff --git a/src/vs/editor/contrib/hover/hoverWidgets.ts b/src/vs/editor/contrib/hover/hoverWidgets.ts index b8880c62fe..9b3e6d9263 100644 --- a/src/vs/editor/contrib/hover/hoverWidgets.ts +++ b/src/vs/editor/contrib/hover/hoverWidgets.ts @@ -8,15 +8,15 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { Widget } from 'vs/base/browser/ui/widget'; import { KeyCode } from 'vs/base/common/keyCodes'; -import * as editorBrowser from 'vs/editor/browser/editorBrowser'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { IContentWidget, ICodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -export class ContentHoverWidget extends Widget implements editorBrowser.IContentWidget { +export class ContentHoverWidget extends Widget implements IContentWidget { private readonly _id: string; - protected _editor: editorBrowser.ICodeEditor; + protected _editor: ICodeEditor; private _isVisible: boolean; private readonly _containerDomNode: HTMLElement; private readonly _domNode: HTMLElement; @@ -37,7 +37,7 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent toggleClass(this._containerDomNode, 'hidden', !this._isVisible); } - constructor(id: string, editor: editorBrowser.ICodeEditor) { + constructor(id: string, editor: ICodeEditor) { super(); this._id = id; this._editor = editor; @@ -61,8 +61,8 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent } }); - this._register(this._editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - if (e.fontInfo) { + this._register(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.fontInfo)) { this.updateFont(); } })); @@ -113,14 +113,14 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent } } - public getPosition(): editorBrowser.IContentWidgetPosition | null { + public getPosition(): IContentWidgetPosition | null { if (this.isVisible) { return { position: this._showAtPosition, range: this._showAtRange, preference: [ - editorBrowser.ContentWidgetPositionPreference.ABOVE, - editorBrowser.ContentWidgetPositionPreference.BELOW + ContentWidgetPositionPreference.ABOVE, + ContentWidgetPositionPreference.BELOW ] }; } @@ -152,7 +152,7 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent private layout(): void { const height = Math.max(this._editor.getLayoutInfo().height / 4, 250); - const { fontSize, lineHeight } = this._editor.getConfiguration().fontInfo; + const { fontSize, lineHeight } = this._editor.getOption(EditorOption.fontInfo); this._domNode.style.fontSize = `${fontSize}px`; this._domNode.style.lineHeight = `${lineHeight}px`; @@ -161,15 +161,15 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent } } -export class GlyphHoverWidget extends Widget implements editorBrowser.IOverlayWidget { +export class GlyphHoverWidget extends Widget implements IOverlayWidget { private readonly _id: string; - protected _editor: editorBrowser.ICodeEditor; + protected _editor: ICodeEditor; private _isVisible: boolean; private readonly _domNode: HTMLElement; protected _showAtLineNumber: number; - constructor(id: string, editor: editorBrowser.ICodeEditor) { + constructor(id: string, editor: ICodeEditor) { super(); this._id = id; this._editor = editor; @@ -182,8 +182,8 @@ export class GlyphHoverWidget extends Widget implements editorBrowser.IOverlayWi this._showAtLineNumber = -1; - this._register(this._editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - if (e.fontInfo) { + this._register(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.fontInfo)) { this.updateFont(); } })); @@ -218,7 +218,7 @@ export class GlyphHoverWidget extends Widget implements editorBrowser.IOverlayWi const editorLayout = this._editor.getLayoutInfo(); const topForLineNumber = this._editor.getTopForLineNumber(this._showAtLineNumber); const editorScrollTop = this._editor.getScrollTop(); - const lineHeight = this._editor.getConfiguration().lineHeight; + const lineHeight = this._editor.getOption(EditorOption.lineHeight); const nodeHeight = this._domNode.clientHeight; const top = topForLineNumber - editorScrollTop - ((nodeHeight - lineHeight) / 2); @@ -233,7 +233,7 @@ export class GlyphHoverWidget extends Widget implements editorBrowser.IOverlayWi this.isVisible = false; } - public getPosition(): editorBrowser.IOverlayWidgetPosition | null { + public getPosition(): IOverlayWidgetPosition | null { return null; } diff --git a/src/vs/editor/contrib/hover/modesContentHover.ts b/src/vs/editor/contrib/hover/modesContentHover.ts index a7a6e2a7de..3307007ef6 100644 --- a/src/vs/editor/contrib/hover/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/modesContentHover.ts @@ -37,6 +37,7 @@ import { QuickFixAction, QuickFixController } from 'vs/editor/contrib/codeAction import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IIdentifiedSingleEditOperation } from 'vs/editor/common/model'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const $ = dom.$; @@ -222,7 +223,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { result => this._withResult(result, true), null, result => this._withResult(result, false), - this._editor.getConfiguration().contribInfo.hover.delay + this._editor.getOption(EditorOption.hover).delay ); this._register(dom.addStandardDisposableListener(this.getDomNode(), dom.EventType.FOCUS, () => { @@ -234,7 +235,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { dom.removeClass(this.getDomNode(), 'colorpicker-hover'); })); this._register(editor.onDidChangeConfiguration((e) => { - this._hoverOperation.setHoverTime(this._editor.getConfiguration().contribInfo.hover.delay); + this._hoverOperation.setHoverTime(this._editor.getOption(EditorOption.hover).delay); })); } @@ -365,7 +366,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { // create blank olor picker model and widget first to ensure it's positioned correctly. const model = new ColorPickerModel(color, [], 0); - const widget = new ColorPickerWidget(fragment, model, this._editor.getConfiguration().pixelRatio, this._themeService); + const widget = new ColorPickerWidget(fragment, model, this._editor.getOption(EditorOption.pixelRatio), this._themeService); getColorPresentations(editorModel, colorInfo, msg.provider, CancellationToken.None).then(colorPresentations => { model.colorPresentations = colorPresentations || []; diff --git a/src/vs/editor/contrib/indentation/indentation.ts b/src/vs/editor/contrib/indentation/indentation.ts index ac59e69056..64c9928bee 100644 --- a/src/vs/editor/contrib/indentation/indentation.ts +++ b/src/vs/editor/contrib/indentation/indentation.ts @@ -22,6 +22,7 @@ import { IndentConsts } from 'vs/editor/common/modes/supports/indentRules'; import { IModelService } from 'vs/editor/common/services/modelService'; import * as indentUtils from 'vs/editor/contrib/indentation/indentUtils'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export function getReindentEditOperations(model: ITextModel, startLineNumber: number, endLineNumber: number, inheritedIndent?: string): IIdentifiedSingleEditOperation[] { if (model.getLineCount() === 1 && model.getLineMaxColumn(1) === 1) { @@ -443,7 +444,7 @@ export class AutoIndentOnPaste implements IEditorContribution { this.callOnModel = dispose(this.callOnModel); // we are disabled - if (!this.editor.getConfiguration().autoIndent || this.editor.getConfiguration().contribInfo.formatOnPaste) { + if (!this.editor.getOption(EditorOption.autoIndent) || this.editor.getOption(EditorOption.formatOnPaste)) { return; } diff --git a/src/vs/editor/contrib/linesOperations/linesOperations.ts b/src/vs/editor/contrib/linesOperations/linesOperations.ts index 43f6cd1834..f6819b067e 100644 --- a/src/vs/editor/contrib/linesOperations/linesOperations.ts +++ b/src/vs/editor/contrib/linesOperations/linesOperations.ts @@ -23,6 +23,7 @@ import { MoveLinesCommand } from 'vs/editor/contrib/linesOperations/moveLinesCom import { SortLinesCommand } from 'vs/editor/contrib/linesOperations/sortLinesCommand'; import { MenuId } from 'vs/platform/actions/common/actions'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; // copy lines @@ -111,7 +112,7 @@ abstract class AbstractMoveLinesAction extends EditorAction { let commands: ICommand[] = []; let selections = editor.getSelections() || []; - let autoIndent = editor.getConfiguration().autoIndent; + const autoIndent = editor.getOption(EditorOption.autoIndent); for (const selection of selections) { commands.push(new MoveLinesCommand(selection, this.down, autoIndent)); @@ -886,7 +887,7 @@ export abstract class AbstractCaseAction extends EditorAction { return; } - let wordSeparators = editor.getConfiguration().wordSeparators; + let wordSeparators = editor.getOption(EditorOption.wordSeparators); let commands: ICommand[] = []; diff --git a/src/vs/editor/contrib/links/links.ts b/src/vs/editor/contrib/links/links.ts index 0f8eee95a7..ad2febc268 100644 --- a/src/vs/editor/contrib/links/links.ts +++ b/src/vs/editor/contrib/links/links.ts @@ -24,6 +24,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { IOpenerService } from 'vs/platform/opener/common/opener'; import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; function getHoverMessage(link: Link, useMetaKey: boolean): MarkdownString { const executeCmd = link.url && /^command:/i.test(link.url.toString()); @@ -139,9 +140,9 @@ class LinkDetector implements editorCommon.IEditorContribution { this.cleanUpActiveLinkDecoration(); })); - this.enabled = editor.getConfiguration().contribInfo.links; + this.enabled = editor.getOption(EditorOption.links); this.listenersToRemove.add(editor.onDidChangeConfiguration((e) => { - let enabled = editor.getConfiguration().contribInfo.links; + const enabled = editor.getOption(EditorOption.links); if (this.enabled === enabled) { // No change in our configuration option return; @@ -218,7 +219,7 @@ class LinkDetector implements editorCommon.IEditorContribution { } private updateDecorations(links: Link[]): void { - const useMetaKey = (this.editor.getConfiguration().multiCursorModifier === 'altKey'); + const useMetaKey = (this.editor.getOption(EditorOption.multiCursorModifier) === 'altKey'); let oldDecorations: string[] = []; let keys = Object.keys(this.currentOccurrences); for (let i = 0, len = keys.length; i < len; i++) { @@ -246,7 +247,7 @@ class LinkDetector implements editorCommon.IEditorContribution { } private _onEditorMouseMove(mouseEvent: ClickLinkMouseEvent, withKey: ClickLinkKeyboardEvent | null): void { - const useMetaKey = (this.editor.getConfiguration().multiCursorModifier === 'altKey'); + const useMetaKey = (this.editor.getOption(EditorOption.multiCursorModifier) === 'altKey'); if (this.isEnabled(mouseEvent, withKey)) { this.cleanUpActiveLinkDecoration(); // always remove previous link decoration as their can only be one const occurrence = this.getLinkOccurrence(mouseEvent.target.position); @@ -262,7 +263,7 @@ class LinkDetector implements editorCommon.IEditorContribution { } private cleanUpActiveLinkDecoration(): void { - const useMetaKey = (this.editor.getConfiguration().multiCursorModifier === 'altKey'); + const useMetaKey = (this.editor.getOption(EditorOption.multiCursorModifier) === 'altKey'); if (this.activeLinkDecorationId) { const occurrence = this.currentOccurrences[this.activeLinkDecorationId]; if (occurrence) { diff --git a/src/vs/editor/contrib/markdown/markdownRenderer.ts b/src/vs/editor/contrib/markdown/markdownRenderer.ts index 5a94e63fb8..23701c2369 100644 --- a/src/vs/editor/contrib/markdown/markdownRenderer.ts +++ b/src/vs/editor/contrib/markdown/markdownRenderer.ts @@ -15,6 +15,7 @@ import { optional } from 'vs/platform/instantiation/common/instantiation'; import { Event, Emitter } from 'vs/base/common/event'; import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { TokenizationRegistry } from 'vs/editor/common/modes'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface IMarkdownRenderResult extends IDisposable { element: HTMLElement; @@ -57,7 +58,7 @@ export class MarkdownRenderer extends Disposable { } return tokenizeToString(value, undefined); }).then(code => { - return `${code}`; + return `${code}`; }); }, codeBlockRenderCallback: () => this._onDidRenderCodeBlock.fire(), diff --git a/src/vs/editor/contrib/multicursor/multicursor.ts b/src/vs/editor/contrib/multicursor/multicursor.ts index 7ce401349f..87f807d313 100644 --- a/src/vs/editor/contrib/multicursor/multicursor.ts +++ b/src/vs/editor/contrib/multicursor/multicursor.ts @@ -26,6 +26,7 @@ import { MenuId } from 'vs/platform/actions/common/actions'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { overviewRulerSelectionHighlightForeground } from 'vs/platform/theme/common/colorRegistry'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class InsertCursorAbove extends EditorAction { @@ -72,7 +73,7 @@ export class InsertCursorAbove extends EditorAction { CursorChangeReason.Explicit, CursorMoveCommands.addCursorUp(context, cursors.getAll(), useLogicalLine) ); - cursors.reveal(true, RevealTarget.TopMost, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.TopMost, ScrollType.Smooth); } } @@ -121,7 +122,7 @@ export class InsertCursorBelow extends EditorAction { CursorChangeReason.Explicit, CursorMoveCommands.addCursorDown(context, cursors.getAll(), useLogicalLine) ); - cursors.reveal(true, RevealTarget.BottomMost, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.BottomMost, ScrollType.Smooth); } } @@ -350,7 +351,7 @@ export class MultiCursorSession { const allSelections = this._editor.getSelections(); const lastAddedSelection = allSelections[allSelections.length - 1]; - const nextMatch = this._editor.getModel().findNextMatch(this.searchText, lastAddedSelection.getEndPosition(), false, this.matchCase, this.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false); + const nextMatch = this._editor.getModel().findNextMatch(this.searchText, lastAddedSelection.getEndPosition(), false, this.matchCase, this.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false); if (!nextMatch) { return null; @@ -401,7 +402,7 @@ export class MultiCursorSession { const allSelections = this._editor.getSelections(); const lastAddedSelection = allSelections[allSelections.length - 1]; - const previousMatch = this._editor.getModel().findPreviousMatch(this.searchText, lastAddedSelection.getStartPosition(), false, this.matchCase, this.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false); + const previousMatch = this._editor.getModel().findPreviousMatch(this.searchText, lastAddedSelection.getStartPosition(), false, this.matchCase, this.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false); if (!previousMatch) { return null; @@ -416,7 +417,7 @@ export class MultiCursorSession { this.findController.highlightFindOptions(); - return this._editor.getModel().findMatches(this.searchText, true, false, this.matchCase, this.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false, Constants.MAX_SAFE_SMALL_INTEGER); + return this._editor.getModel().findMatches(this.searchText, true, false, this.matchCase, this.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false, Constants.MAX_SAFE_SMALL_INTEGER); } } @@ -593,7 +594,7 @@ export class MultiCursorSelectionController extends Disposable implements IEdito // - and we're searching for a regex if (findState.isRevealed && findState.searchString.length > 0 && findState.isRegex) { - matches = this._editor.getModel().findMatches(findState.searchString, true, findState.isRegex, findState.matchCase, findState.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false, Constants.MAX_SAFE_SMALL_INTEGER); + matches = this._editor.getModel().findMatches(findState.searchString, true, findState.isRegex, findState.matchCase, findState.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false, Constants.MAX_SAFE_SMALL_INTEGER); } else { @@ -808,13 +809,13 @@ export class SelectionHighlighter extends Disposable implements IEditorContribut constructor(editor: ICodeEditor) { super(); this.editor = editor; - this._isEnabled = editor.getConfiguration().contribInfo.selectionHighlight; + this._isEnabled = editor.getOption(EditorOption.selectionHighlight); this.decorations = []; this.updateSoon = this._register(new RunOnceScheduler(() => this._update(), 300)); this.state = null; this._register(editor.onDidChangeConfiguration((e) => { - this._isEnabled = editor.getConfiguration().contribInfo.selectionHighlight; + this._isEnabled = editor.getOption(EditorOption.selectionHighlight); })); this._register(editor.onDidChangeCursorSelection((e: ICursorSelectionChangedEvent) => { @@ -928,7 +929,7 @@ export class SelectionHighlighter extends Disposable implements IEditorContribut } } - return new SelectionHighlighterState(r.searchText, r.matchCase, r.wholeWord ? editor.getConfiguration().wordSeparators : null); + return new SelectionHighlighterState(r.searchText, r.matchCase, r.wholeWord ? editor.getOption(EditorOption.wordSeparators) : null); } private _setState(state: SelectionHighlighterState | null): void { @@ -1053,4 +1054,4 @@ registerEditorAction(MoveSelectionToPreviousFindMatchAction); registerEditorAction(SelectHighlightsAction); registerEditorAction(CompatChangeAll); registerEditorAction(InsertCursorAtEndOfLineSelected); -registerEditorAction(InsertCursorAtTopOfLineSelected); \ No newline at end of file +registerEditorAction(InsertCursorAtTopOfLineSelected); diff --git a/src/vs/editor/contrib/multicursor/test/multicursor.test.ts b/src/vs/editor/contrib/multicursor/test/multicursor.test.ts index 97cb8da5d1..1bd13e8cc0 100644 --- a/src/vs/editor/contrib/multicursor/test/multicursor.test.ts +++ b/src/vs/editor/contrib/multicursor/test/multicursor.test.ts @@ -60,7 +60,7 @@ suite('Multicursor selection', () => { let queryState: { [key: string]: any; } = {}; let serviceCollection = new ServiceCollection(); serviceCollection.set(IStorageService, { - _serviceBrand: undefined as any, + _serviceBrand: undefined, onDidChangeStorage: Event.None, onWillSaveState: Event.None, get: (key: string) => queryState[key], @@ -68,7 +68,8 @@ suite('Multicursor selection', () => { getNumber: (key: string) => undefined!, store: (key: string, value: any) => { queryState[key] = value; return Promise.resolve(); }, remove: (key) => undefined, - logStorage: () => undefined + logStorage: () => undefined, + migrate: (toWorkspace) => Promise.resolve(undefined) } as IStorageService); test('issue #8817: Cursor position changes when you cancel multicursor', () => { diff --git a/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts b/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts index b89bf12a5d..dc05dee363 100644 --- a/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts +++ b/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts @@ -12,6 +12,7 @@ import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursor import { CharacterSet } from 'vs/editor/common/core/characterClassifier'; import * as modes from 'vs/editor/common/modes'; import { provideSignatureHelp } from 'vs/editor/contrib/parameterHints/provideSignatureHelp'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface TriggerContext { readonly triggerKind: modes.SignatureHelpTriggerKind; @@ -125,7 +126,7 @@ export class ParameterHintsModel extends Disposable { const length = this.state.hints.signatures.length; const activeSignature = this.state.hints.activeSignature; const last = (activeSignature % length) === (length - 1); - const cycle = this.editor.getConfiguration().contribInfo.parameterHints.cycle; + const cycle = this.editor.getOption(EditorOption.parameterHints).cycle; // If there is only one signature, or we're on last signature of list if ((length < 2 || last) && !cycle) { @@ -144,7 +145,7 @@ export class ParameterHintsModel extends Disposable { const length = this.state.hints.signatures.length; const activeSignature = this.state.hints.activeSignature; const first = activeSignature === 0; - const cycle = this.editor.getConfiguration().contribInfo.parameterHints.cycle; + const cycle = this.editor.getOption(EditorOption.parameterHints).cycle; // If there is only one signature, or we're on first signature of list if ((length < 2 || first) && !cycle) { @@ -271,7 +272,7 @@ export class ParameterHintsModel extends Disposable { } private onEditorConfigurationChange(): void { - this.triggerOnType = this.editor.getConfiguration().contribInfo.parameterHints.enabled; + this.triggerOnType = this.editor.getOption(EditorOption.parameterHints).enabled; if (!this.triggerOnType) { this.cancel(); diff --git a/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts b/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts index f4af5b6a2c..f0a4d60dc7 100644 --- a/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts +++ b/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts @@ -11,7 +11,7 @@ import { Event } from 'vs/base/common/event'; import { IDisposable, Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import 'vs/css!./parameterHints'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import * as modes from 'vs/editor/common/modes'; import { IModeService } from 'vs/editor/common/services/modeService'; import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer'; @@ -105,14 +105,14 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, })); const updateFont = () => { - const fontInfo = this.editor.getConfiguration().fontInfo; + const fontInfo = this.editor.getOption(EditorOption.fontInfo); this.element.style.fontSize = `${fontInfo.fontSize}px`; }; updateFont(); - this._register(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) - .filter(e => e.fontInfo) + this._register(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) + .filter(e => e.hasChanged(EditorOption.fontInfo)) .on(updateFont, null)); this._register(this.editor.onDidLayoutChange(e => this.updateMaxHeight())); @@ -177,7 +177,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, const code = dom.append(this.signature, $('.code')); const hasParameters = signature.parameters.length > 0; - const fontInfo = this.editor.getConfiguration().fontInfo; + const fontInfo = this.editor.getOption(EditorOption.fontInfo); code.style.fontSize = `${fontInfo.fontSize}px`; code.style.fontFamily = fontInfo.fontFamily; diff --git a/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts b/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts index 0c578c3b02..61a506b25b 100644 --- a/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts @@ -21,16 +21,17 @@ import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/con import { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable } from 'vs/base/common/lifecycle'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export const IPeekViewService = createDecorator('IPeekViewService'); export interface IPeekViewService { - _serviceBrand: any; + _serviceBrand: undefined; addExclusiveWidget(editor: ICodeEditor, widget: PeekViewWidget): void; } registerSingleton(IPeekViewService, class implements IPeekViewService { - _serviceBrand: any; + _serviceBrand: undefined; private _widgets = new Map(); @@ -80,7 +81,7 @@ const defaultOptions: IPeekViewOptions = { export abstract class PeekViewWidget extends ZoneWidget { - public _serviceBrand: any; + public _serviceBrand: undefined; private _onDidClose = new Emitter(); @@ -216,8 +217,8 @@ export abstract class PeekViewWidget extends ZoneWidget { return; } - const headHeight = Math.ceil(this.editor.getConfiguration().lineHeight * 1.2); - const bodyHeight = heightInPixel - (headHeight + 2 /* the border-top/bottom width*/); + const headHeight = Math.ceil(this.editor.getOption(EditorOption.lineHeight) * 1.2); + const bodyHeight = Math.round(heightInPixel - (headHeight + 2 /* the border-top/bottom width*/)); this._doLayoutHead(headHeight, widthInPixel); this._doLayoutBody(bodyHeight, widthInPixel); diff --git a/src/vs/editor/contrib/referenceSearch/referencesModel.ts b/src/vs/editor/contrib/referenceSearch/referencesModel.ts index a7ebf11dfa..b1928f9f6d 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesModel.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesModel.ts @@ -74,9 +74,9 @@ export class FilePreview implements IDisposable { const beforeRange = new Range(startLineNumber, word.startColumn, startLineNumber, startColumn); const afterRange = new Range(endLineNumber, endColumn, endLineNumber, Number.MAX_VALUE); - const before = model.getValueInRange(beforeRange).replace(/^\s+/, strings.empty); + const before = model.getValueInRange(beforeRange).replace(/^\s+/, ''); const inside = model.getValueInRange(range); - const after = model.getValueInRange(afterRange).replace(/\s+$/, strings.empty); + const after = model.getValueInRange(afterRange).replace(/\s+$/, ''); return { value: before + inside + after, diff --git a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts index 1c6fc3fb46..a54ff274ab 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts @@ -311,8 +311,9 @@ export class ReferenceWidget extends PeekViewWidget { keyboardNavigationLabelProvider: this._instantiationService.createInstance(StringRepresentationProvider), identityProvider: new IdentityProvider() }; - this._tree = this._instantiationService.createInstance, ITreeRenderer[], IAsyncDataSource, IAsyncDataTreeOptions, WorkbenchAsyncDataTree>( + this._tree = this._instantiationService.createInstance, ITreeRenderer[], IAsyncDataSource, IAsyncDataTreeOptions, WorkbenchAsyncDataTree>( WorkbenchAsyncDataTree, + 'ReferencesWidget', this._treeContainer, new Delegate(), [ @@ -382,8 +383,11 @@ export class ReferenceWidget extends PeekViewWidget { }); this._tree.onDidOpen(e => { const aside = (e.browserEvent instanceof MouseEvent) && (e.browserEvent.ctrlKey || e.browserEvent.metaKey || e.browserEvent.altKey); - const goto = !e.browserEvent || ((e.browserEvent instanceof MouseEvent) && e.browserEvent.detail === 2); - + let goto = !e.browserEvent || ((e.browserEvent instanceof MouseEvent) && e.browserEvent.detail === 2); + if (e.browserEvent instanceof KeyboardEvent) { + // todo@joh make this a command + goto = true; + } if (aside) { onEvent(e.elements[0], 'side'); } else if (goto) { diff --git a/src/vs/editor/contrib/rename/renameInputField.ts b/src/vs/editor/contrib/rename/renameInputField.ts index 40e057e3e9..c3344feb74 100644 --- a/src/vs/editor/contrib/rename/renameInputField.ts +++ b/src/vs/editor/contrib/rename/renameInputField.ts @@ -13,6 +13,7 @@ import { localize } from 'vs/nls'; import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { inputBackground, inputBorder, inputForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export const CONTEXT_RENAME_INPUT_VISIBLE = new RawContextKey('renameInputVisible', false); @@ -40,7 +41,7 @@ export class RenameInputField implements IContentWidget, IDisposable { this._editor.addContentWidget(this); this._disposables.add(editor.onDidChangeConfiguration(e => { - if (e.fontInfo) { + if (e.hasChanged(EditorOption.fontInfo)) { this.updateFont(); } })); @@ -68,7 +69,7 @@ export class RenameInputField implements IContentWidget, IDisposable { this._inputField.type = 'text'; this._inputField.setAttribute('aria-label', localize('renameAriaLabel', "Rename input. Type new name and press Enter to commit.")); this._domNode = document.createElement('div'); - this._domNode.style.height = `${this._editor.getConfiguration().lineHeight}px`; + this._domNode.style.height = `${this._editor.getOption(EditorOption.lineHeight)}px`; this._domNode.className = 'monaco-editor rename-box'; this._domNode.appendChild(this._inputField); @@ -103,7 +104,7 @@ export class RenameInputField implements IContentWidget, IDisposable { return; } - const fontInfo = this._editor.getConfiguration().fontInfo; + const fontInfo = this._editor.getOption(EditorOption.fontInfo); this._inputField.style.fontFamily = fontInfo.fontFamily; this._inputField.style.fontWeight = fontInfo.fontWeight; this._inputField.style.fontSize = `${fontInfo.fontSize}px`; diff --git a/src/vs/editor/contrib/smartSelect/smartSelect.ts b/src/vs/editor/contrib/smartSelect/smartSelect.ts index ab36647627..d2fc691d4f 100644 --- a/src/vs/editor/contrib/smartSelect/smartSelect.ts +++ b/src/vs/editor/contrib/smartSelect/smartSelect.ts @@ -165,7 +165,10 @@ class GrowSelectionAction extends AbstractSmartSelect { kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.RightArrow, - mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.RightArrow }, + mac: { + primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.RightArrow, + secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.RightArrow], + }, weight: KeybindingWeight.EditorContrib }, menubarOpts: { @@ -191,7 +194,10 @@ class ShrinkSelectionAction extends AbstractSmartSelect { kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.LeftArrow, - mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.LeftArrow }, + mac: { + primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.LeftArrow, + secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.LeftArrow], + }, weight: KeybindingWeight.EditorContrib }, menubarOpts: { diff --git a/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts b/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts index 4cbba32e1a..1e0092d15b 100644 --- a/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts +++ b/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts @@ -22,7 +22,7 @@ import { WordSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/wordSe class TestTextResourcePropertiesService implements ITextResourcePropertiesService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @IConfigurationService private readonly configurationService: IConfigurationService, @@ -96,21 +96,21 @@ suite('SmartSelect', () => { '\t}', '}' ], 3, 20, [ - new Range(1, 1, 5, 2), // all - new Range(1, 21, 5, 2), // {} outside - new Range(1, 22, 5, 1), // {} inside - new Range(2, 1, 4, 3), // block - new Range(2, 1, 4, 3), - new Range(2, 2, 4, 3), - new Range(2, 11, 4, 3), - new Range(2, 12, 4, 2), - new Range(3, 1, 3, 27), // line w/ triva - new Range(3, 3, 3, 27), // line w/o triva - new Range(3, 10, 3, 27), // () outside - new Range(3, 11, 3, 26), // () inside - new Range(3, 17, 3, 26), // () outside - new Range(3, 18, 3, 25), // () inside - ]); + new Range(1, 1, 5, 2), // all + new Range(1, 21, 5, 2), // {} outside + new Range(1, 22, 5, 1), // {} inside + new Range(2, 1, 4, 3), // block + new Range(2, 1, 4, 3), + new Range(2, 2, 4, 3), + new Range(2, 11, 4, 3), + new Range(2, 12, 4, 2), + new Range(3, 1, 3, 27), // line w/ triva + new Range(3, 3, 3, 27), // line w/o triva + new Range(3, 10, 3, 27), // () outside + new Range(3, 11, 3, 26), // () inside + new Range(3, 17, 3, 26), // () outside + new Range(3, 18, 3, 25), // () inside + ]); }); test('getRangesToPosition #56886. Skip empty lines correctly.', () => { @@ -122,15 +122,15 @@ suite('SmartSelect', () => { '\t}', '}' ], 3, 1, [ - new Range(1, 1, 5, 2), - new Range(1, 21, 5, 2), - new Range(1, 22, 5, 1), - new Range(2, 1, 4, 3), - new Range(2, 1, 4, 3), - new Range(2, 2, 4, 3), - new Range(2, 11, 4, 3), - new Range(2, 12, 4, 2), - ]); + new Range(1, 1, 5, 2), + new Range(1, 21, 5, 2), + new Range(1, 22, 5, 1), + new Range(2, 1, 4, 3), + new Range(2, 1, 4, 3), + new Range(2, 2, 4, 3), + new Range(2, 11, 4, 3), + new Range(2, 12, 4, 2), + ]); }); test('getRangesToPosition #56886. Do not skip lines with only whitespaces.', () => { @@ -142,17 +142,17 @@ suite('SmartSelect', () => { '\t}', '}' ], 3, 1, [ - new Range(1, 1, 5, 2), // all - new Range(1, 21, 5, 2), // {} outside - new Range(1, 22, 5, 1), // {} inside - new Range(2, 1, 4, 3), - new Range(2, 1, 4, 3), - new Range(2, 2, 4, 3), - new Range(2, 11, 4, 3), - new Range(2, 12, 4, 2), - new Range(3, 1, 3, 2), // block - new Range(3, 1, 3, 2) // empty line - ]); + new Range(1, 1, 5, 2), // all + new Range(1, 21, 5, 2), // {} outside + new Range(1, 22, 5, 1), // {} inside + new Range(2, 1, 4, 3), + new Range(2, 1, 4, 3), + new Range(2, 2, 4, 3), + new Range(2, 11, 4, 3), + new Range(2, 12, 4, 2), + new Range(3, 1, 3, 2), // block + new Range(3, 1, 3, 2) // empty line + ]); }); test('getRangesToPosition #40658. Cursor at first position inside brackets should select line inside.', () => { @@ -162,11 +162,11 @@ suite('SmartSelect', () => { ' { } ', '( ) ' ], 2, 3, [ - new Range(1, 1, 3, 5), - new Range(2, 1, 2, 6), // line w/ triava - new Range(2, 2, 2, 5), // {} inside, line w/o triva - new Range(2, 3, 2, 4) // {} inside - ]); + new Range(1, 1, 3, 5), + new Range(2, 1, 2, 6), // line w/ triava + new Range(2, 2, 2, 5), // {} inside, line w/o triva + new Range(2, 3, 2, 4) // {} inside + ]); }); test('getRangesToPosition #40658. Cursor in empty brackets should reveal brackets first.', () => { @@ -176,11 +176,11 @@ suite('SmartSelect', () => { ' { } ', ' ( ) ' ], 1, 3, [ - new Range(1, 1, 3, 7), // all - new Range(1, 1, 1, 5), // line w/ trival - new Range(1, 2, 1, 4), // [] outside, line w/o trival - new Range(1, 3, 1, 3), // [] inside - ]); + new Range(1, 1, 3, 7), // all + new Range(1, 1, 1, 5), // line w/ trival + new Range(1, 2, 1, 4), // [] outside, line w/o trival + new Range(1, 3, 1, 3), // [] inside + ]); }); test('getRangesToPosition #40658. Tokens before bracket will be revealed first.', () => { @@ -190,11 +190,11 @@ suite('SmartSelect', () => { ' { } ', 'selectthis( ) ' ], 3, 11, [ - new Range(1, 1, 3, 15), // all - new Range(3, 1, 3, 15), // line w/ trivia - new Range(3, 1, 3, 14), // line w/o trivia - new Range(3, 1, 3, 11) // word - ]); + new Range(1, 1, 3, 15), // all + new Range(3, 1, 3, 15), // line w/ trivia + new Range(3, 1, 3, 14), // line w/o trivia + new Range(3, 1, 3, 11) // word + ]); }); // -- bracket selections diff --git a/src/vs/editor/contrib/snippet/snippetSession.ts b/src/vs/editor/contrib/snippet/snippetSession.ts index 473ba745a5..baa2855b2d 100644 --- a/src/vs/editor/contrib/snippet/snippetSession.ts +++ b/src/vs/editor/contrib/snippet/snippetSession.ts @@ -23,6 +23,7 @@ import { registerThemingParticipant } from 'vs/platform/theme/common/themeServic import * as colors from 'vs/platform/theme/common/colorRegistry'; import { withNullAsUndefined } from 'vs/base/common/types'; import { ILabelService } from 'vs/platform/label/common/label'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; registerThemingParticipant((theme, collector) => { @@ -444,7 +445,7 @@ export class SnippetSession { snippet.resolveVariables(new CompositeSnippetVariableResolver([ modelBasedVariableResolver, - new ClipboardBasedVariableResolver(clipboardText, idx, indexedSelections.length), + new ClipboardBasedVariableResolver(clipboardText, idx, indexedSelections.length, editor.getOption(EditorOption.multiCursorPaste) === 'spread'), new SelectionBasedVariableResolver(model, selection), new CommentBasedVariableResolver(model), new TimeBasedVariableResolver, diff --git a/src/vs/editor/contrib/snippet/snippetVariables.ts b/src/vs/editor/contrib/snippet/snippetVariables.ts index 91b7d162ec..7e2e9a2a3d 100644 --- a/src/vs/editor/contrib/snippet/snippetVariables.ts +++ b/src/vs/editor/contrib/snippet/snippetVariables.ts @@ -169,7 +169,8 @@ export class ClipboardBasedVariableResolver implements VariableResolver { constructor( private readonly _clipboardText: string | undefined, private readonly _selectionIdx: number, - private readonly _selectionCount: number + private readonly _selectionCount: number, + private readonly _spread: boolean ) { // } @@ -183,12 +184,16 @@ export class ClipboardBasedVariableResolver implements VariableResolver { return undefined; } - const lines = this._clipboardText.split(/\r\n|\n|\r/).filter(s => !isFalsyOrWhitespace(s)); - if (lines.length === this._selectionCount) { - return lines[this._selectionIdx]; - } else { - return this._clipboardText; + // `spread` is assigning each cursor a line of the clipboard + // text whenever there the line count equals the cursor count + // and when enabled + if (this._spread) { + const lines = this._clipboardText.split(/\r\n|\n|\r/).filter(s => !isFalsyOrWhitespace(s)); + if (lines.length === this._selectionCount) { + return lines[this._selectionIdx]; + } } + return this._clipboardText; } } export class CommentBasedVariableResolver implements VariableResolver { diff --git a/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts b/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts index ff3455173e..e855fb161b 100644 --- a/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts @@ -236,26 +236,28 @@ suite('Snippet Variables Resolver', function () { test('Add variable to insert value from clipboard to a snippet #40153', function () { - assertVariableResolve(new ClipboardBasedVariableResolver(undefined, 1, 0), 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver(undefined, 1, 0, true), 'CLIPBOARD', undefined); - assertVariableResolve(new ClipboardBasedVariableResolver(null!, 1, 0), 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver(null!, 1, 0, true), 'CLIPBOARD', undefined); - assertVariableResolve(new ClipboardBasedVariableResolver('', 1, 0), 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver('', 1, 0, true), 'CLIPBOARD', undefined); - assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0), 'CLIPBOARD', 'foo'); + assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0, true), 'CLIPBOARD', 'foo'); - assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0), 'foo', undefined); - assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0), 'cLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0, true), 'foo', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0, true), 'cLIPBOARD', undefined); }); test('Add variable to insert value from clipboard to a snippet #40153', function () { - assertVariableResolve(new ClipboardBasedVariableResolver('line1', 1, 2), 'CLIPBOARD', 'line1'); - assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2\nline3', 1, 2), 'CLIPBOARD', 'line1\nline2\nline3'); + assertVariableResolve(new ClipboardBasedVariableResolver('line1', 1, 2, true), 'CLIPBOARD', 'line1'); + assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2\nline3', 1, 2, true), 'CLIPBOARD', 'line1\nline2\nline3'); - assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 1, 2), 'CLIPBOARD', 'line2'); - resolver = new ClipboardBasedVariableResolver('line1\nline2', 0, 2); - assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 0, 2), 'CLIPBOARD', 'line1'); + assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 1, 2, true), 'CLIPBOARD', 'line2'); + resolver = new ClipboardBasedVariableResolver('line1\nline2', 0, 2, true); + assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 0, 2, true), 'CLIPBOARD', 'line1'); + + assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 0, 2, false), 'CLIPBOARD', 'line1\nline2'); }); @@ -299,7 +301,7 @@ suite('Snippet Variables Resolver', function () { let workspace: IWorkspace; let resolver: VariableResolver; const workspaceService = new class implements IWorkspaceContextService { - _serviceBrand: any; + _serviceBrand: undefined; _throw = () => { throw new Error(); }; onDidChangeWorkbenchState = this._throw; onDidChangeWorkspaceName = this._throw; diff --git a/src/vs/editor/contrib/suggest/completionModel.ts b/src/vs/editor/contrib/suggest/completionModel.ts index 25721be674..8d93593f0d 100644 --- a/src/vs/editor/contrib/suggest/completionModel.ts +++ b/src/vs/editor/contrib/suggest/completionModel.ts @@ -6,7 +6,7 @@ import { fuzzyScore, fuzzyScoreGracefulAggressive, FuzzyScorer, FuzzyScore, anyScore } from 'vs/base/common/filters'; import { CompletionItemProvider, CompletionItemKind } from 'vs/editor/common/modes'; import { CompletionItem } from './suggest'; -import { InternalSuggestOptions, EDITOR_DEFAULTS } from 'vs/editor/common/config/editorOptions'; +import { InternalSuggestOptions } from 'vs/editor/common/config/editorOptions'; import { WordDistance } from 'vs/editor/contrib/suggest/wordDistance'; import { CharCode } from 'vs/base/common/charCode'; import { compareIgnoreCase } from 'vs/base/common/strings'; @@ -60,7 +60,8 @@ export class CompletionModel { column: number, lineContext: LineContext, wordDistance: WordDistance, - options: InternalSuggestOptions = EDITOR_DEFAULTS.contribInfo.suggest + options: InternalSuggestOptions, + snippetSuggestions: 'top' | 'bottom' | 'inline' | 'none' ) { this._items = items; this._column = column; @@ -69,9 +70,9 @@ export class CompletionModel { this._refilterKind = Refilter.All; this._lineContext = lineContext; - if (options.snippets === 'top') { + if (snippetSuggestions === 'top') { this._snippetCompareFn = CompletionModel._compareCompletionItemsSnippetsUp; - } else if (options.snippets === 'bottom') { + } else if (snippetSuggestions === 'bottom') { this._snippetCompareFn = CompletionModel._compareCompletionItemsSnippetsDown; } } diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index d38a4465b5..663a8baebe 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -45,6 +45,13 @@ float: right; } +/* MarkupContent Layout */ +.monaco-editor .suggest-widget > .details ul { + padding-left: 20px; +} +.monaco-editor .suggest-widget > .details ol { + padding-left: 20px; +} /* Styles for Message element for when widget is loading or is empty */ .monaco-editor .suggest-widget > .message { @@ -158,6 +165,7 @@ .monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated { opacity: 0.66; + text-decoration: unset; } .monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated > .monaco-icon-label-description-container { text-decoration: line-through; diff --git a/src/vs/editor/contrib/suggest/suggest.ts b/src/vs/editor/contrib/suggest/suggest.ts index 9a4052ca07..83acb3f39f 100644 --- a/src/vs/editor/contrib/suggest/suggest.ts +++ b/src/vs/editor/contrib/suggest/suggest.ts @@ -161,6 +161,10 @@ export function provideSuggestionItems( if (!suggestion.range) { suggestion.range = defaultRange; } + // fill in default sortText when missing + if (!suggestion.sortText) { + suggestion.sortText = suggestion.label; + } allSuggestions.push(new CompletionItem(position, suggestion, container, provider, model)); } @@ -278,7 +282,7 @@ registerDefaultLanguageCommand('_executeCompletionItemProvider', async (model, p await Promise.all(resolving); return result; } finally { - setTimeout(() => disposables.dispose(), 0); + setTimeout(() => disposables.dispose(), 100); } }); diff --git a/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts b/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts index 30792d634d..8d02ff482d 100644 --- a/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts +++ b/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts @@ -8,6 +8,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ISelectedSuggestion, SuggestWidget } from './suggestWidget'; import { CharacterSet } from 'vs/editor/common/core/characterClassifier'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class CommitCharacterController { @@ -27,7 +28,7 @@ export class CommitCharacterController { this._disposables.add(editor.onWillType(text => { if (this._active) { const ch = text.charCodeAt(text.length - 1); - if (this._active.acceptCharacters.has(ch) && editor.getConfiguration().contribInfo.acceptSuggestionOnCommitCharacter) { + if (this._active.acceptCharacters.has(ch) && editor.getOption(EditorOption.acceptSuggestionOnCommitCharacter)) { accept(this._active.item); } } diff --git a/src/vs/editor/contrib/suggest/suggestController.ts b/src/vs/editor/contrib/suggest/suggestController.ts index 12d054803b..6f1b2685ef 100644 --- a/src/vs/editor/contrib/suggest/suggestController.ts +++ b/src/vs/editor/contrib/suggest/suggestController.ts @@ -35,6 +35,7 @@ import { isObject } from 'vs/base/common/types'; import { CommitCharacterController } from './suggestCommitCharacters'; import { IPosition } from 'vs/editor/common/core/position'; import { TrackedRangeStickiness, ITextModel } from 'vs/editor/common/model'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const _sticky = false; // for development purposes only @@ -58,15 +59,19 @@ class LineSuffix { } dispose(): void { - if (this._marker) { + if (this._marker && !this._model.isDisposed()) { this._model.deltaDecorations(this._marker, []); } } delta(position: IPosition): number { - if (this._position.lineNumber !== position.lineNumber) { + if (this._model.isDisposed() || this._position.lineNumber !== position.lineNumber) { + // bail out early if things seems fishy return 0; - } else if (this._marker) { + } + // read the marker (in case suggest was triggered at line end) or compare + // the cursor to the line end. + if (this._marker) { const range = this._model.getDecorationRange(this._marker[0]); const end = this._model.getOffsetAt(range!.getStartPosition()); return end - this._model.getOffsetAt(position); @@ -125,7 +130,7 @@ export class SuggestController implements IEditorContribution { const endColumn = position.column; let value = true; if ( - this._editor.getConfiguration().contribInfo.acceptSuggestionOnEnter === 'smart' + this._editor.getOption(EditorOption.acceptSuggestionOnEnter) === 'smart' && this._model.state === State.Auto && !item.completion.command && !item.completion.additionalTextEdits @@ -178,7 +183,7 @@ export class SuggestController implements IEditorContribution { // Manage the acceptSuggestionsOnEnter context key let acceptSuggestionsOnEnter = SuggestContext.AcceptSuggestionsOnEnter.bindTo(_contextKeyService); let updateFromConfig = () => { - const { acceptSuggestionOnEnter } = this._editor.getConfiguration().contribInfo; + const acceptSuggestionOnEnter = this._editor.getOption(EditorOption.acceptSuggestionOnEnter); acceptSuggestionsOnEnter.set(acceptSuggestionOnEnter === 'on' || acceptSuggestionOnEnter === 'smart'); }; this._toDispose.add(this._editor.onDidChangeConfiguration(() => updateFromConfig())); diff --git a/src/vs/editor/contrib/suggest/suggestMemory.ts b/src/vs/editor/contrib/suggest/suggestMemory.ts index 9b8c863a70..c40aebb30b 100644 --- a/src/vs/editor/contrib/suggest/suggestMemory.ts +++ b/src/vs/editor/contrib/suggest/suggestMemory.ts @@ -208,7 +208,7 @@ export type MemMode = 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix'; export class SuggestMemoryService extends Disposable implements ISuggestMemoryService { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; private readonly _storagePrefix = 'suggest/memories'; @@ -292,7 +292,7 @@ export class SuggestMemoryService extends Disposable implements ISuggestMemorySe export const ISuggestMemoryService = createDecorator('ISuggestMemories'); export interface ISuggestMemoryService { - _serviceBrand: any; + _serviceBrand: undefined; memorize(model: ITextModel, pos: IPosition, item: CompletionItem): void; select(model: ITextModel, pos: IPosition, items: CompletionItem[]): number; } diff --git a/src/vs/editor/contrib/suggest/suggestModel.ts b/src/vs/editor/contrib/suggest/suggestModel.ts index 6356716f27..512a63f58c 100644 --- a/src/vs/editor/contrib/suggest/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/suggestModel.ts @@ -20,6 +20,7 @@ import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2 import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; import { WordDistance } from 'vs/editor/contrib/suggest/wordDistance'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface ICancelEvent { readonly retrigger: boolean; @@ -172,7 +173,7 @@ export class SuggestModel implements IDisposable { // --- handle configuration & precondition changes private _updateQuickSuggest(): void { - this._quickSuggestDelay = this._editor.getConfiguration().contribInfo.quickSuggestionsDelay; + this._quickSuggestDelay = this._editor.getOption(EditorOption.quickSuggestionsDelay); if (isNaN(this._quickSuggestDelay) || (!this._quickSuggestDelay && this._quickSuggestDelay !== 0) || this._quickSuggestDelay < 0) { this._quickSuggestDelay = 10; @@ -183,9 +184,9 @@ export class SuggestModel implements IDisposable { dispose(this._triggerCharacterListener); - if (this._editor.getConfiguration().readOnly + if (this._editor.getOption(EditorOption.readOnly) || !this._editor.hasModel() - || !this._editor.getConfiguration().contribInfo.suggestOnTriggerCharacters) { + || !this._editor.getOption(EditorOption.suggestOnTriggerCharacters)) { return; } @@ -277,7 +278,7 @@ export class SuggestModel implements IDisposable { if (this._state === State.Idle) { - if (this._editor.getConfiguration().contribInfo.quickSuggestions === false) { + if (this._editor.getOption(EditorOption.quickSuggestions) === false) { // not enabled return; } @@ -287,7 +288,7 @@ export class SuggestModel implements IDisposable { return; } - if (this._editor.getConfiguration().contribInfo.suggest.snippetsPreventQuickSuggestions && SnippetController2.get(this._editor).isInSnippet()) { + if (this._editor.getOption(EditorOption.suggest).snippetsPreventQuickSuggestions && SnippetController2.get(this._editor).isInSnippet()) { // no quick suggestion when in snippet mode return; } @@ -307,7 +308,7 @@ export class SuggestModel implements IDisposable { const model = this._editor.getModel(); const pos = this._editor.getPosition(); // validate enabled now - const { quickSuggestions } = this._editor.getConfiguration().contribInfo; + const quickSuggestions = this._editor.getOption(EditorOption.quickSuggestions); if (quickSuggestions === false) { return; } else if (quickSuggestions === true) { @@ -387,10 +388,11 @@ export class SuggestModel implements IDisposable { this._requestToken = new CancellationTokenSource(); // kind filter and snippet sort rules - const { contribInfo } = this._editor.getConfiguration(); + const suggestOptions = this._editor.getOption(EditorOption.suggest); + const snippetSuggestions = this._editor.getOption(EditorOption.snippetSuggestions); let itemKindFilter = new Set(); let snippetSortOrder = SnippetSortOrder.Inline; - switch (contribInfo.suggest.snippets) { + switch (snippetSuggestions) { case 'top': snippetSortOrder = SnippetSortOrder.Top; break; @@ -407,9 +409,9 @@ export class SuggestModel implements IDisposable { } // kind filter - for (const key in contribInfo.suggest.filteredTypes) { + for (const key in suggestOptions.filteredTypes) { const kind = completionKindFromString(key, true); - if (typeof kind !== 'undefined' && contribInfo.suggest.filteredTypes[key] === false) { + if (typeof kind !== 'undefined' && suggestOptions.filteredTypes[key] === false) { itemKindFilter.add(kind); } } @@ -449,7 +451,8 @@ export class SuggestModel implements IDisposable { characterCountDelta: ctx.column - this._context!.column }, wordDistance, - this._editor.getConfiguration().contribInfo.suggest + this._editor.getOption(EditorOption.suggest), + this._editor.getOption(EditorOption.snippetSuggestions) ); // store containers so that they can be disposed later diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 24ba97bc1f..32b93cee18 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -16,7 +16,7 @@ import { List } from 'vs/base/browser/ui/list/listWidget'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { Context as SuggestContext, CompletionItem } from './suggest'; import { CompletionModel } from './completionModel'; @@ -124,11 +124,12 @@ class Renderer implements IListRenderer data.readMore.title = nls.localize('readMore', "Read More...{0}", this.triggerKeybindingLabel); const configureFont = () => { - const configuration = this.editor.getConfiguration(); - const fontFamily = configuration.fontInfo.fontFamily; - const fontSize = configuration.contribInfo.suggestFontSize || configuration.fontInfo.fontSize; - const lineHeight = configuration.contribInfo.suggestLineHeight || configuration.fontInfo.lineHeight; - const fontWeight = configuration.fontInfo.fontWeight; + const options = this.editor.getOptions(); + const fontInfo = options.get(EditorOption.fontInfo); + const fontFamily = fontInfo.fontFamily; + const fontSize = options.get(EditorOption.suggestFontSize) || fontInfo.fontSize; + const lineHeight = options.get(EditorOption.suggestLineHeight) || fontInfo.lineHeight; + const fontWeight = fontInfo.fontWeight; const fontSizePx = `${fontSize}px`; const lineHeightPx = `${lineHeight}px`; @@ -144,8 +145,8 @@ class Renderer implements IListRenderer configureFont(); - data.disposables.add(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) - .filter(e => e.fontInfo || e.contribInfo) + data.disposables.add(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) + .filter(e => e.hasChanged(EditorOption.fontInfo) || e.hasChanged(EditorOption.suggestFontSize) || e.hasChanged(EditorOption.suggestLineHeight)) .on(configureFont, null)); return data; @@ -276,8 +277,8 @@ class SuggestionDetails { this.configureFont(); - Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) - .filter(e => e.fontInfo) + Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) + .filter(e => e.hasChanged(EditorOption.fontInfo)) .on(this.configureFont, this, this.disposables); markdownRenderer.onDidRenderCodeBlock(() => this.scrollbar.scanDomNode(), this, this.disposables); @@ -389,11 +390,12 @@ class SuggestionDetails { } private configureFont() { - const configuration = this.editor.getConfiguration(); - const fontFamily = configuration.fontInfo.fontFamily; - const fontSize = configuration.contribInfo.suggestFontSize || configuration.fontInfo.fontSize; - const lineHeight = configuration.contribInfo.suggestLineHeight || configuration.fontInfo.lineHeight; - const fontWeight = configuration.fontInfo.fontWeight; + const options = this.editor.getOptions(); + const fontInfo = options.get(EditorOption.fontInfo); + const fontFamily = fontInfo.fontFamily; + const fontSize = options.get(EditorOption.suggestFontSize) || fontInfo.fontSize; + const lineHeight = options.get(EditorOption.suggestLineHeight) || fontInfo.lineHeight; + const fontWeight = fontInfo.fontWeight; const fontSizePx = `${fontSize}px`; const lineHeightPx = `${lineHeight}px`; @@ -500,12 +502,12 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate toggleClass(this.element, 'no-icons', !this.editor.getConfiguration().contribInfo.suggest.showIcons); + const applyIconStyle = () => toggleClass(this.element, 'no-icons', !this.editor.getOption(EditorOption.suggest).showIcons); applyIconStyle(); let renderer = instantiationService.createInstance(Renderer, this, this.editor, triggerKeybindingLabel); - this.list = new List(this.listElement, this, [renderer], { + this.list = new List('SuggestWidget', this.listElement, this, [renderer], { useShadows: false, openController: { shouldOpen: () => false }, mouseSupport: false @@ -521,7 +523,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate this.onListSelection(e))); this.toDispose.add(this.list.onFocusChange(e => this.onListFocus(e))); this.toDispose.add(this.editor.onDidChangeCursorSelection(() => this.onCursorSelectionChanged())); - this.toDispose.add(this.editor.onDidChangeConfiguration(e => e.contribInfo && applyIconStyle())); + this.toDispose.add(this.editor.onDidChangeConfiguration(e => e.hasChanged(EditorOption.suggest) && applyIconStyle())); this.suggestWidgetVisible = SuggestContext.Visible.bindTo(contextKeyService); @@ -1051,7 +1053,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate e.contribInfo && this._update())); + this._register(this._editor.onDidChangeConfiguration(e => e.hasChanged(EditorOption.tabCompletion) && this._update())); this._update(); } @@ -34,7 +35,7 @@ export class WordContextKey extends Disposable { private _update(): void { // only update this when tab completions are enabled - const enabled = this._editor.getConfiguration().contribInfo.tabCompletion === 'on'; + const enabled = this._editor.getOption(EditorOption.tabCompletion) === 'on'; if (this._enabled === enabled) { return; } diff --git a/src/vs/editor/contrib/suggest/wordDistance.ts b/src/vs/editor/contrib/suggest/wordDistance.ts index ff7569babc..4ddf629a7b 100644 --- a/src/vs/editor/contrib/suggest/wordDistance.ts +++ b/src/vs/editor/contrib/suggest/wordDistance.ts @@ -10,6 +10,7 @@ import { IPosition } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { CompletionItem, CompletionItemKind } from 'vs/editor/common/modes'; import { BracketSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/bracketSelections'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export abstract class WordDistance { @@ -17,55 +18,53 @@ export abstract class WordDistance { distance() { return 0; } }; - static create(service: IEditorWorkerService, editor: ICodeEditor): Promise { + static async create(service: IEditorWorkerService, editor: ICodeEditor): Promise { - if (!editor.getConfiguration().contribInfo.suggest.localityBonus) { - return Promise.resolve(WordDistance.None); + if (!editor.getOption(EditorOption.suggest).localityBonus) { + return WordDistance.None; } if (!editor.hasModel()) { - return Promise.resolve(WordDistance.None); + return WordDistance.None; } const model = editor.getModel(); const position = editor.getPosition(); if (!service.canComputeWordRanges(model.uri)) { - return Promise.resolve(WordDistance.None); + return WordDistance.None; } - return new BracketSelectionRangeProvider().provideSelectionRanges(model, [position]).then(ranges => { - if (!ranges || ranges.length === 0 || ranges[0].length === 0) { - return WordDistance.None; - } - return service.computeWordRanges(model.uri, ranges[0][0].range).then(wordRanges => { - return new class extends WordDistance { - distance(anchor: IPosition, suggestion: CompletionItem) { - if (!wordRanges || !position.equals(editor.getPosition())) { - return 0; - } - if (suggestion.kind === CompletionItemKind.Keyword) { - return 2 << 20; - } - let word = suggestion.label; - let wordLines = wordRanges[word]; - if (isFalsyOrEmpty(wordLines)) { - return 2 << 20; - } - let idx = binarySearch(wordLines, Range.fromPositions(anchor), Range.compareRangesUsingStarts); - let bestWordRange = idx >= 0 ? wordLines[idx] : wordLines[Math.max(0, ~idx - 1)]; - let blockDistance = ranges.length; - for (const range of ranges[0]) { - if (!Range.containsRange(range.range, bestWordRange)) { - break; - } - blockDistance -= 1; - } - return blockDistance; + const ranges = await new BracketSelectionRangeProvider().provideSelectionRanges(model, [position]); + if (!ranges || ranges.length === 0 || ranges[0].length === 0) { + return WordDistance.None; + } + const wordRanges = await service.computeWordRanges(model.uri, ranges[0][0].range); + return new class extends WordDistance { + distance(anchor: IPosition, suggestion: CompletionItem) { + if (!wordRanges || !position.equals(editor.getPosition())) { + return 0; + } + if (suggestion.kind === CompletionItemKind.Keyword) { + return 2 << 20; + } + let word = suggestion.label; + let wordLines = wordRanges[word]; + if (isFalsyOrEmpty(wordLines)) { + return 2 << 20; + } + let idx = binarySearch(wordLines, Range.fromPositions(anchor), Range.compareRangesUsingStarts); + let bestWordRange = idx >= 0 ? wordLines[idx] : wordLines[Math.max(0, ~idx - 1)]; + let blockDistance = ranges.length; + for (const range of ranges[0]) { + if (!Range.containsRange(range.range, bestWordRange)) { + break; } - }; - }); - }); + blockDistance -= 1; + } + return blockDistance; + } + }; } abstract distance(anchor: IPosition, suggestion: CompletionItem): number; diff --git a/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts b/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts index db2ec8fb9e..029aa208b2 100644 --- a/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts +++ b/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts @@ -26,16 +26,15 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { activeContrastBorder, editorSelectionHighlight, editorSelectionHighlightBorder, overviewRulerSelectionHighlightForeground, registerColor } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant, themeColorFromId } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; -export const editorWordHighlight = registerColor('editor.wordHighlightBackground', { dark: '#575757B8', light: '#57575740', hc: null }, nls.localize('wordHighlight', 'Background color of a symbol during read-access, like reading a variable. The color must not be opaque so as not to hide underlying decorations.'), true); -export const editorWordHighlightStrong = registerColor('editor.wordHighlightStrongBackground', { dark: '#004972B8', light: '#0e639c40', hc: null }, nls.localize('wordHighlightStrong', 'Background color of a symbol during write-access, like writing to a variable. The color must not be opaque so as not to hide underlying decorations.'), true); -export const editorWordHighlightBorder = registerColor('editor.wordHighlightBorder', { light: null, dark: null, hc: activeContrastBorder }, nls.localize('wordHighlightBorder', 'Border color of a symbol during read-access, like reading a variable.')); -export const editorWordHighlightStrongBorder = registerColor('editor.wordHighlightStrongBorder', { light: null, dark: null, hc: activeContrastBorder }, nls.localize('wordHighlightStrongBorder', 'Border color of a symbol during write-access, like writing to a variable.')); - -export const overviewRulerWordHighlightForeground = registerColor('editorOverviewRuler.wordHighlightForeground', { dark: '#A0A0A0CC', light: '#A0A0A0CC', hc: '#A0A0A0CC' }, nls.localize('overviewRulerWordHighlightForeground', 'Overview ruler marker color for symbol highlights. The color must not be opaque so as not to hide underlying decorations.'), true); -export const overviewRulerWordHighlightStrongForeground = registerColor('editorOverviewRuler.wordHighlightStrongForeground', { dark: '#C0A0C0CC', light: '#C0A0C0CC', hc: '#C0A0C0CC' }, nls.localize('overviewRulerWordHighlightStrongForeground', 'Overview ruler marker color for write-access symbol highlights. The color must not be opaque so as not to hide underlying decorations.'), true); - -export const ctxHasWordHighlights = new RawContextKey('hasWordHighlights', false); +const editorWordHighlight = registerColor('editor.wordHighlightBackground', { dark: '#575757B8', light: '#57575740', hc: null }, nls.localize('wordHighlight', 'Background color of a symbol during read-access, like reading a variable. The color must not be opaque so as not to hide underlying decorations.'), true); +const editorWordHighlightStrong = registerColor('editor.wordHighlightStrongBackground', { dark: '#004972B8', light: '#0e639c40', hc: null }, nls.localize('wordHighlightStrong', 'Background color of a symbol during write-access, like writing to a variable. The color must not be opaque so as not to hide underlying decorations.'), true); +const editorWordHighlightBorder = registerColor('editor.wordHighlightBorder', { light: null, dark: null, hc: activeContrastBorder }, nls.localize('wordHighlightBorder', 'Border color of a symbol during read-access, like reading a variable.')); +const editorWordHighlightStrongBorder = registerColor('editor.wordHighlightStrongBorder', { light: null, dark: null, hc: activeContrastBorder }, nls.localize('wordHighlightStrongBorder', 'Border color of a symbol during write-access, like writing to a variable.')); +const overviewRulerWordHighlightForeground = registerColor('editorOverviewRuler.wordHighlightForeground', { dark: '#A0A0A0CC', light: '#A0A0A0CC', hc: '#A0A0A0CC' }, nls.localize('overviewRulerWordHighlightForeground', 'Overview ruler marker color for symbol highlights. The color must not be opaque so as not to hide underlying decorations.'), true); +const overviewRulerWordHighlightStrongForeground = registerColor('editorOverviewRuler.wordHighlightStrongForeground', { dark: '#C0A0C0CC', light: '#C0A0C0CC', hc: '#C0A0C0CC' }, nls.localize('overviewRulerWordHighlightStrongForeground', 'Overview ruler marker color for write-access symbol highlights. The color must not be opaque so as not to hide underlying decorations.'), true); +const ctxHasWordHighlights = new RawContextKey('hasWordHighlights', false); export function getOccurrencesAtPosition(model: ITextModel, position: Position, token: CancellationToken): Promise { @@ -181,7 +180,7 @@ class WordHighlighter { this.editor = editor; this._hasWordHighlights = ctxHasWordHighlights.bindTo(contextKeyService); this._ignorePositionChangeEvent = false; - this.occurrencesHighlight = this.editor.getConfiguration().contribInfo.occurrencesHighlight; + this.occurrencesHighlight = this.editor.getOption(EditorOption.occurrencesHighlight); this.model = this.editor.getModel(); this.toUnhook.add(editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => { @@ -202,7 +201,7 @@ class WordHighlighter { this._stopAll(); })); this.toUnhook.add(editor.onDidChangeConfiguration((e) => { - let newValue = this.editor.getConfiguration().contribInfo.occurrencesHighlight; + let newValue = this.editor.getOption(EditorOption.occurrencesHighlight); if (this.occurrencesHighlight !== newValue) { this.occurrencesHighlight = newValue; this._stopAll(); @@ -371,7 +370,7 @@ class WordHighlighter { let myRequestId = ++this.workerRequestTokenId; this.workerRequestCompleted = false; - this.workerRequest = computeOccurencesAtPosition(this.model, this.editor.getSelection(), this.editor.getConfiguration().wordSeparators); + this.workerRequest = computeOccurencesAtPosition(this.model, this.editor.getSelection(), this.editor.getOption(EditorOption.wordSeparators)); this.workerRequest.result.then(data => { if (myRequestId === this.workerRequestTokenId) { diff --git a/src/vs/editor/contrib/wordOperations/wordOperations.ts b/src/vs/editor/contrib/wordOperations/wordOperations.ts index 2830d0809d..fbc050176c 100644 --- a/src/vs/editor/contrib/wordOperations/wordOperations.ts +++ b/src/vs/editor/contrib/wordOperations/wordOperations.ts @@ -20,7 +20,7 @@ import { ITextModel } from 'vs/editor/common/model'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { EDITOR_DEFAULTS } from 'vs/editor/common/config/editorOptions'; +import { EditorOption, EditorOptions } from 'vs/editor/common/config/editorOptions'; export interface MoveWordOptions extends ICommandOptions { inSelectionMode: boolean; @@ -42,8 +42,7 @@ export abstract class MoveWordCommand extends EditorCommand { if (!editor.hasModel()) { return; } - const config = editor.getConfiguration(); - const wordSeparators = getMapForWordSeparators(config.wordSeparators); + const wordSeparators = getMapForWordSeparators(editor.getOption(EditorOption.wordSeparators)); const model = editor.getModel(); const selections = editor.getSelections(); @@ -190,7 +189,7 @@ export class CursorWordAccessibilityLeft extends WordLeftCommand { } protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position { - return super._move(getMapForWordSeparators(EDITOR_DEFAULTS.wordSeparators), model, position, wordNavigationType); + return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType); } } @@ -199,7 +198,7 @@ export class CursorWordAccessibilityLeftSelect extends WordLeftCommand { super({ inSelectionMode: true, wordNavigationType: WordNavigationType.WordAccessibility, - id: 'cursorWordAccessibilitLeftSelecty', + id: 'cursorWordAccessibilityLeftSelect', precondition: undefined, kbOpts: { kbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, CONTEXT_ACCESSIBILITY_MODE_ENABLED), @@ -211,7 +210,7 @@ export class CursorWordAccessibilityLeftSelect extends WordLeftCommand { } protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position { - return super._move(getMapForWordSeparators(EDITOR_DEFAULTS.wordSeparators), model, position, wordNavigationType); + return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType); } } @@ -310,7 +309,7 @@ export class CursorWordAccessibilityRight extends WordRightCommand { } protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position { - return super._move(getMapForWordSeparators(EDITOR_DEFAULTS.wordSeparators), model, position, wordNavigationType); + return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType); } } @@ -331,7 +330,7 @@ export class CursorWordAccessibilityRightSelect extends WordRightCommand { } protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position { - return super._move(getMapForWordSeparators(EDITOR_DEFAULTS.wordSeparators), model, position, wordNavigationType); + return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType); } } @@ -354,8 +353,7 @@ export abstract class DeleteWordCommand extends EditorCommand { if (!editor.hasModel()) { return; } - const config = editor.getConfiguration(); - const wordSeparators = getMapForWordSeparators(config.wordSeparators); + const wordSeparators = getMapForWordSeparators(editor.getOption(EditorOption.wordSeparators)); const model = editor.getModel(); const selections = editor.getSelections(); diff --git a/src/vs/editor/contrib/zoneWidget/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/zoneWidget.ts index 30cf954e2e..3ff9cee13b 100644 --- a/src/vs/editor/contrib/zoneWidget/zoneWidget.ts +++ b/src/vs/editor/contrib/zoneWidget/zoneWidget.ts @@ -11,7 +11,7 @@ import { IdGenerator } from 'vs/base/common/idGenerator'; import { DisposableStore } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, IViewZone, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser'; -import { EditorLayoutInfo } from 'vs/editor/common/config/editorOptions'; +import { EditorLayoutInfo, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { ScrollType } from 'vs/editor/common/editorCommon'; @@ -334,7 +334,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { } private _decoratingElementsHeight(): number { - let lineHeight = this.editor.getConfiguration().lineHeight; + let lineHeight = this.editor.getOption(EditorOption.lineHeight); let result = 0; if (this.options.showArrow) { @@ -364,7 +364,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { // Render the widget as zone (rendering) and widget (lifecycle) const viewZoneDomNode = document.createElement('div'); viewZoneDomNode.style.overflow = 'hidden'; - const lineHeight = this.editor.getConfiguration().lineHeight; + const lineHeight = this.editor.getOption(EditorOption.lineHeight); // adjust heightInLines to viewport const maxHeightInLines = (this.editor.getLayoutInfo().height / lineHeight) * 0.8; @@ -505,7 +505,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { this._disposables.add(this._resizeSash.onDidChange((evt: ISashEvent) => { if (data) { - let lineDelta = (evt.currentY - data.startY) / this.editor.getConfiguration().lineHeight; + let lineDelta = (evt.currentY - data.startY) / this.editor.getOption(EditorOption.lineHeight); let roundedLineDelta = lineDelta < 0 ? Math.ceil(lineDelta) : Math.floor(lineDelta); let newHeightInLines = data.heightInLines + roundedLineDelta; diff --git a/src/vs/editor/editor.api.ts b/src/vs/editor/editor.api.ts index 3377a95d80..f5abe0c592 100644 --- a/src/vs/editor/editor.api.ts +++ b/src/vs/editor/editor.api.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { EDITOR_DEFAULTS, WrappingIndent } from 'vs/editor/common/config/editorOptions'; +import { EditorOptions, WrappingIndent } from 'vs/editor/common/config/editorOptions'; import { createMonacoBaseAPI } from 'vs/editor/common/standalone/standaloneBase'; import { createMonacoEditorAPI } from 'vs/editor/standalone/browser/standaloneEditor'; import { createMonacoLanguagesAPI } from 'vs/editor/standalone/browser/standaloneLanguages'; @@ -11,9 +11,10 @@ import { createMonacoLanguagesAPI } from 'vs/editor/standalone/browser/standalon const global: any = self; // Set defaults for standalone editor -(EDITOR_DEFAULTS).wrappingIndent = WrappingIndent.None; -(EDITOR_DEFAULTS.viewInfo).glyphMargin = false; -(EDITOR_DEFAULTS).autoIndent = false; +(EditorOptions.wrappingIndent).defaultValue = WrappingIndent.None; +(EditorOptions.glyphMargin).defaultValue = false; +(EditorOptions.autoIndent).defaultValue = false; +(EditorOptions.overviewRulerLanes).defaultValue = 2; const api = createMonacoBaseAPI(); api.editor = createMonacoEditorAPI(); diff --git a/src/vs/editor/editor.worker.ts b/src/vs/editor/editor.worker.ts index 39ad6d386c..3eaff215d1 100644 --- a/src/vs/editor/editor.worker.ts +++ b/src/vs/editor/editor.worker.ts @@ -19,12 +19,12 @@ export function initialize(foreignModule: any) { (self).postMessage(msg); }, (host: EditorWorkerHost) => new EditorSimpleWorker(host, foreignModule)); - self.onmessage = (e) => { + self.onmessage = (e: MessageEvent) => { simpleWorker.onmessage(e.data); }; } -self.onmessage = (e) => { +self.onmessage = (e: MessageEvent) => { // Ignore first message in this case and initialize if not yet initialized if (!initialized) { initialize(null); diff --git a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts index a118257414..172f6d11ba 100644 --- a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts +++ b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts @@ -31,6 +31,7 @@ import { contrastBorder, editorWidgetBackground, widgetShadow, editorWidgetForeg import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { AccessibilityHelpNLS } from 'vs/editor/common/standaloneStrings'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const CONTEXT_ACCESSIBILITY_WIDGET_VISIBLE = new RawContextKey('accessibilityHelpWidgetVisible', false); @@ -163,7 +164,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { if (e.equals(KeyMod.CtrlCmd | KeyCode.KEY_H)) { alert(AccessibilityHelpNLS.openingDocs); - let url = (this._editor.getRawConfiguration()).accessibilityHelpUrl; + let url = (this._editor.getRawOptions()).accessibilityHelpUrl; if (typeof url === 'undefined') { url = 'https://go.microsoft.com/fwlink/?linkid=852450'; } @@ -223,7 +224,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { } private _buildContent() { - let opts = this._editor.getConfiguration(); + const options = this._editor.getOptions(); const selections = this._editor.getSelections(); let charactersSelected = 0; @@ -239,14 +240,14 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { let text = getSelectionLabel(selections, charactersSelected); - if (opts.wrappingInfo.inDiffEditor) { - if (opts.readOnly) { + if (options.get(EditorOption.inDiffEditor)) { + if (options.get(EditorOption.readOnly)) { text += AccessibilityHelpNLS.readonlyDiffEditor; } else { text += AccessibilityHelpNLS.editableDiffEditor; } } else { - if (opts.readOnly) { + if (options.get(EditorOption.readOnly)) { text += AccessibilityHelpNLS.readonlyEditor; } else { text += AccessibilityHelpNLS.editableEditor; @@ -258,7 +259,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { ? AccessibilityHelpNLS.changeConfigToOnMac : AccessibilityHelpNLS.changeConfigToOnWinLinux ); - switch (opts.accessibilitySupport) { + switch (options.get(EditorOption.accessibilitySupport)) { case AccessibilitySupport.Unknown: text += '\n\n - ' + turnOnMessage; break; @@ -272,7 +273,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { } - if (opts.tabFocusMode) { + if (options.get(EditorOption.tabFocusMode)) { text += '\n\n - ' + this._descriptionForCommand(ToggleTabFocusModeAction.ID, AccessibilityHelpNLS.tabFocusModeOnMsg, AccessibilityHelpNLS.tabFocusModeOnMsgNoKb); } else { text += '\n\n - ' + this._descriptionForCommand(ToggleTabFocusModeAction.ID, AccessibilityHelpNLS.tabFocusModeOffMsg, AccessibilityHelpNLS.tabFocusModeOffMsgNoKb); diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts b/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts index 7ae8de2d28..a6442672b6 100644 --- a/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts +++ b/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts @@ -10,6 +10,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class IPadShowKeyboard extends Disposable implements IEditorContribution { @@ -29,7 +30,7 @@ export class IPadShowKeyboard extends Disposable implements IEditorContribution } private update(): void { - const shouldHaveWidget = (!this.editor.getConfiguration().readOnly); + const shouldHaveWidget = (!this.editor.getOption(EditorOption.readOnly)); if (!this.widget && shouldHaveWidget) { diff --git a/src/vs/editor/standalone/browser/quickOpen/quickOpenEditorWidget.ts b/src/vs/editor/standalone/browser/quickOpen/quickOpenEditorWidget.ts index e04ee805f1..62c683a556 100644 --- a/src/vs/editor/standalone/browser/quickOpen/quickOpenEditorWidget.ts +++ b/src/vs/editor/standalone/browser/quickOpen/quickOpenEditorWidget.ts @@ -45,10 +45,10 @@ export class QuickOpenEditorWidget implements IOverlayWidget { onCancel: onCancel, onType: onType }, { - inputPlaceHolder: undefined, - inputAriaLabel: configuration.inputAriaLabel, - keyboardSupport: true - } + inputPlaceHolder: undefined, + inputAriaLabel: configuration.inputAriaLabel, + keyboardSupport: true + } ); this.styler = attachQuickOpenStyler(this.quickOpenWidget, this.themeService, { pickerGroupForeground: foreground diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index e56dcf3802..a3489b4e3c 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -28,7 +28,7 @@ import { CommandsRegistry, ICommand, ICommandEvent, ICommandHandler, ICommandSer import { IConfigurationChangeEvent, IConfigurationData, IConfigurationOverrides, IConfigurationService, IConfigurationModel } from 'vs/platform/configuration/common/configuration'; import { Configuration, ConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IConfirmation, IConfirmationResult, IDialogOptions, IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IConfirmation, IConfirmationResult, IDialogOptions, IDialogService, IShowResult } from 'vs/platform/dialogs/common/dialogs'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { AbstractKeybindingService } from 'vs/platform/keybinding/common/abstractKeybindingService'; import { IKeybindingEvent, IKeyboardEvent, KeybindingSource } from 'vs/platform/keybinding/common/keybinding'; @@ -97,7 +97,7 @@ function withTypedEditor(widget: editorCommon.IEditor, codeEditorCallback: (e } export class SimpleEditorModelResolverService implements ITextModelService { - public _serviceBrand: any; + public _serviceBrand: undefined; private editor?: editorCommon.IEditor; @@ -142,7 +142,7 @@ export class SimpleEditorModelResolverService implements ITextModelService { } export class SimpleEditorProgressService implements IEditorProgressService { - _serviceBrand: any; + _serviceBrand: undefined; private static NULL_PROGRESS_RUNNER: IProgressRunner = { done: () => { }, @@ -163,7 +163,7 @@ export class SimpleEditorProgressService implements IEditorProgressService { export class SimpleDialogService implements IDialogService { - public _serviceBrand: any; + public _serviceBrand: undefined; public confirm(confirmation: IConfirmation): Promise { return this.doConfirm(confirmation).then(confirmed => { @@ -183,14 +183,14 @@ export class SimpleDialogService implements IDialogService { return Promise.resolve(window.confirm(messageText)); } - public show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise { - return Promise.resolve(0); + public show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise { + return Promise.resolve({ choice: 0 }); } } export class SimpleNotificationService implements INotificationService { - public _serviceBrand: any; + public _serviceBrand: undefined; private static readonly NO_OP: INotificationHandle = new NoOpNotification(); @@ -232,7 +232,7 @@ export class SimpleNotificationService implements INotificationService { } export class StandaloneCommandService implements ICommandService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _instantiationService: IInstantiationService; private readonly _dynamicCommands: { [id: string]: ICommand; }; @@ -414,7 +414,7 @@ function isConfigurationOverrides(thing: any): thing is IConfigurationOverrides export class SimpleConfigurationService implements IConfigurationService { - _serviceBrand: any; + _serviceBrand: undefined; private _onDidChangeConfiguration = new Emitter(); public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; @@ -479,7 +479,7 @@ export class SimpleConfigurationService implements IConfigurationService { export class SimpleResourceConfigurationService implements ITextResourceConfigurationService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _onDidChangeConfiguration = new Emitter(); public readonly onDidChangeConfiguration = this._onDidChangeConfiguration.event; @@ -504,7 +504,7 @@ export class SimpleResourceConfigurationService implements ITextResourceConfigur export class SimpleResourcePropertiesService implements ITextResourcePropertiesService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @IConfigurationService private readonly configurationService: IConfigurationService, @@ -523,7 +523,7 @@ export class SimpleResourcePropertiesService implements ITextResourcePropertiesS } export class StandaloneTelemetryService implements ITelemetryService { - _serviceBrand: void = undefined; + _serviceBrand: undefined; public isOptedIn = false; @@ -545,7 +545,7 @@ export class StandaloneTelemetryService implements ITelemetryService { export class SimpleWorkspaceContextService implements IWorkspaceContextService { - public _serviceBrand: any; + public _serviceBrand: undefined; private static SCHEME = 'inmemory'; @@ -614,7 +614,7 @@ export function applyConfigurationValues(configurationService: IConfigurationSer } export class SimpleBulkEditService implements IBulkEditService { - _serviceBrand: any; + _serviceBrand: undefined; constructor(private readonly _modelService: IModelService) { // @@ -658,7 +658,7 @@ export class SimpleBulkEditService implements IBulkEditService { export class SimpleUriLabelService implements ILabelService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _onDidRegisterFormatter = new Emitter(); public readonly onDidChangeFormatters: Event = this._onDidRegisterFormatter.event; @@ -692,7 +692,7 @@ export class SimpleUriLabelService implements ILabelService { } export class SimpleLayoutService implements ILayoutService { - _serviceBrand: any; + _serviceBrand: undefined; public onLayout = Event.None; diff --git a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts index 162a1e7bfa..5bb1b6d3df 100644 --- a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts @@ -23,7 +23,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { ContextKeyExpr, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -376,7 +376,7 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon @INotificationService notificationService: INotificationService, @IConfigurationService configurationService: IConfigurationService, @IContextMenuService contextMenuService: IContextMenuService, - @IClipboardService clipboardService: IClipboardService + @optional(IClipboardService) clipboardService: IClipboardService | null, ) { applyConfigurationValues(configurationService, options, true); options = options || {}; @@ -384,7 +384,7 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon options.theme = themeService.setTheme(options.theme); } - super(domElement, options, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService, clipboardService); + super(domElement, options, clipboardService, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService); this._contextViewService = contextViewService; this._configurationService = configurationService; diff --git a/src/vs/editor/standalone/browser/standaloneEditor.ts b/src/vs/editor/standalone/browser/standaloneEditor.ts index 3dc783bc75..66092ac141 100644 --- a/src/vs/editor/standalone/browser/standaloneEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneEditor.ts @@ -10,7 +10,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { OpenerService } from 'vs/editor/browser/services/openerService'; import { DiffNavigator } from 'vs/editor/browser/widget/diffNavigator'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo'; import { Token } from 'vs/editor/common/core/token'; import * as editorCommon from 'vs/editor/common/editorCommon'; @@ -38,7 +38,6 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { clearAllFontInfos } from 'vs/editor/browser/config/configuration'; -import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; type Omit = Pick>; @@ -121,7 +120,7 @@ export function createDiffEditor(domElement: HTMLElement, options?: IDiffEditorC services.get(INotificationService), services.get(IConfigurationService), services.get(IContextMenuService), - services.get(IClipboardService) + null ); }); } @@ -352,6 +351,7 @@ export function createMonacoEditorAPI(): typeof monaco.editor { remeasureFonts: remeasureFonts, // enums + AccessibilitySupport: standaloneEnums.AccessibilitySupport, ScrollbarVisibility: standaloneEnums.ScrollbarVisibility, WrappingIndent: standaloneEnums.WrappingIndent, OverviewRulerLane: standaloneEnums.OverviewRulerLane, @@ -371,14 +371,14 @@ export function createMonacoEditorAPI(): typeof monaco.editor { RenderLineNumbersType: standaloneEnums.RenderLineNumbersType, // classes - InternalEditorOptions: editorOptions.InternalEditorOptions, + ConfigurationChangedEvent: ConfigurationChangedEvent, BareFontInfo: BareFontInfo, FontInfo: FontInfo, TextModelResolvedOptions: TextModelResolvedOptions, FindMatch: FindMatch, // vars - EditorType: editorCommon.EditorType + EditorType: editorCommon.EditorType, }; } diff --git a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts index 717f5a0d84..0cc58b663a 100644 --- a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts +++ b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts @@ -156,7 +156,7 @@ function newBuiltInTheme(builtinTheme: BuiltinTheme): StandaloneTheme { export class StandaloneThemeServiceImpl implements IStandaloneThemeService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _knownThemes: Map; private readonly _styleElement: HTMLStyleElement; diff --git a/src/vs/editor/standalone/common/standaloneThemeService.ts b/src/vs/editor/standalone/common/standaloneThemeService.ts index e2db64b078..cc8dbff4c3 100644 --- a/src/vs/editor/standalone/common/standaloneThemeService.ts +++ b/src/vs/editor/standalone/common/standaloneThemeService.ts @@ -26,7 +26,7 @@ export interface IStandaloneTheme extends ITheme { } export interface IStandaloneThemeService extends IThemeService { - _serviceBrand: any; + _serviceBrand: undefined; setTheme(themeName: string): string; diff --git a/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts b/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts index f844fb1ec9..6beba732e7 100644 --- a/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts +++ b/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts @@ -33,7 +33,7 @@ suite('TokenizationSupport2Adapter', () => { } class MockThemeService implements IStandaloneThemeService { - _serviceBrand = null; + _serviceBrand: undefined; public setTheme(themeName: string): string { throw new Error('Not implemented'); } @@ -184,4 +184,4 @@ suite('TokenizationSupport2Adapter', () => { ); }); -}); \ No newline at end of file +}); diff --git a/src/vs/editor/test/browser/commands/trimTrailingWhitespaceCommand.test.ts b/src/vs/editor/test/browser/commands/trimTrailingWhitespaceCommand.test.ts index 6bce005eb5..bec93faf1b 100644 --- a/src/vs/editor/test/browser/commands/trimTrailingWhitespaceCommand.test.ts +++ b/src/vs/editor/test/browser/commands/trimTrailingWhitespaceCommand.test.ts @@ -63,11 +63,11 @@ suite('Editor Commands - Trim Trailing Whitespace Command', () => { 'even more text ', 'and some mixed\t \t' ], [ - createSingleEditOp(null, 1, 10, 1, 11), - createSingleEditOp(null, 3, 1, 3, 4), - createSingleEditOp(null, 4, 15, 4, 17), - createSingleEditOp(null, 5, 15, 5, 20) - ]); + createSingleEditOp(null, 1, 10, 1, 11), + createSingleEditOp(null, 3, 1, 3, 4), + createSingleEditOp(null, 4, 15, 4, 17), + createSingleEditOp(null, 5, 15, 5, 20) + ]); assertTrimTrailingWhitespace(['text '], [new Position(1, 1), new Position(1, 2), new Position(1, 3)], [createInsertDeleteSingleEditOp(null, 1, 5, 1, 8)]); @@ -80,11 +80,11 @@ suite('Editor Commands - Trim Trailing Whitespace Command', () => { 'even more text ', 'and some mixed\t \t' ], [], [ - createInsertDeleteSingleEditOp(null, 1, 10, 1, 11), - createInsertDeleteSingleEditOp(null, 3, 1, 3, 4), - createInsertDeleteSingleEditOp(null, 4, 15, 4, 17), - createInsertDeleteSingleEditOp(null, 5, 15, 5, 20) - ]); + createInsertDeleteSingleEditOp(null, 1, 10, 1, 11), + createInsertDeleteSingleEditOp(null, 3, 1, 3, 4), + createInsertDeleteSingleEditOp(null, 4, 15, 4, 17), + createInsertDeleteSingleEditOp(null, 5, 15, 5, 20) + ]); assertTrimTrailingWhitespace([ 'some text\t', 'some more text', @@ -92,10 +92,10 @@ suite('Editor Commands - Trim Trailing Whitespace Command', () => { 'even more text ', 'and some mixed\t \t' ], [new Position(1, 11), new Position(3, 2), new Position(5, 1), new Position(4, 1), new Position(5, 10)], [ - createInsertDeleteSingleEditOp(null, 3, 2, 3, 4), - createInsertDeleteSingleEditOp(null, 4, 15, 4, 17), - createInsertDeleteSingleEditOp(null, 5, 15, 5, 20) - ]); + createInsertDeleteSingleEditOp(null, 3, 2, 3, 4), + createInsertDeleteSingleEditOp(null, 4, 15, 4, 17), + createInsertDeleteSingleEditOp(null, 5, 15, 5, 20) + ]); }); }); diff --git a/src/vs/editor/test/browser/controller/cursor.test.ts b/src/vs/editor/test/browser/controller/cursor.test.ts index 69d67fdb69..3cb5425139 100644 --- a/src/vs/editor/test/browser/controller/cursor.test.ts +++ b/src/vs/editor/test/browser/controller/cursor.test.ts @@ -711,7 +711,7 @@ suite('Editor Controller - Cursor', () => { position: new Position(4, 4), viewPosition: new Position(4, 4), mouseColumn: 15, - setAnchorIfNotSet: false + doColumnSelect: true }); let expectedSelections = [ @@ -747,7 +747,7 @@ suite('Editor Controller - Cursor', () => { position: new Position(4, 1), viewPosition: new Position(4, 1), mouseColumn: 1, - setAnchorIfNotSet: false + doColumnSelect: true }); assertCursor(cursor, [ @@ -787,7 +787,7 @@ suite('Editor Controller - Cursor', () => { position: new Position(1, 1), viewPosition: new Position(1, 1), mouseColumn: 1, - setAnchorIfNotSet: false + doColumnSelect: true }); assertCursor(cursor, [ new Selection(10, 10, 10, 1), @@ -806,7 +806,7 @@ suite('Editor Controller - Cursor', () => { position: new Position(1, 1), viewPosition: new Position(1, 1), mouseColumn: 1, - setAnchorIfNotSet: false + doColumnSelect: true }); assertCursor(cursor, [ new Selection(10, 10, 10, 1), @@ -1566,6 +1566,37 @@ suite('Editor Controller - Regression tests', () => { }); }); + test('issue #43722: Multiline paste doesn\'t work anymore', () => { + usingCursor({ + text: [ + 'test', + 'test', + 'test', + 'test' + ], + }, (model, cursor) => { + cursor.setSelections('test', [ + new Selection(1, 1, 1, 5), + new Selection(2, 1, 2, 5), + new Selection(3, 1, 3, 5), + new Selection(4, 1, 4, 5), + ]); + + cursorCommand(cursor, H.Paste, { + text: 'aaa\r\nbbb\r\nccc\r\nddd\r\n', + pasteOnNewLine: false, + multicursorText: null + }); + + assert.equal(model.getValue(), [ + 'aaa', + 'bbb', + 'ccc', + 'ddd', + ].join('\n')); + }); + }); + test('issue #46440: (1) Pasting a multi-line selection pastes entire selection into every insertion point', () => { usingCursor({ text: [ diff --git a/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts b/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts index ce2119c87f..98332860d7 100644 --- a/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts +++ b/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts @@ -483,11 +483,11 @@ function selectionEqual(selection: Selection, posLineNumber: number, posColumn: positionLineNumber: selection.positionLineNumber, positionColumn: selection.positionColumn }, { - selectionStartLineNumber: selLineNumber, - selectionStartColumn: selColumn, - positionLineNumber: posLineNumber, - positionColumn: posColumn - }, 'selection equal'); + selectionStartLineNumber: selLineNumber, + selectionStartColumn: selColumn, + positionLineNumber: posLineNumber, + positionColumn: posColumn + }, 'selection equal'); } function moveTo(cursor: Cursor, lineNumber: number, column: number, inSelectionMode: boolean = false) { diff --git a/src/vs/editor/test/browser/editorTestServices.ts b/src/vs/editor/test/browser/editorTestServices.ts index 2b4fb94972..a522e63b7e 100644 --- a/src/vs/editor/test/browser/editorTestServices.ts +++ b/src/vs/editor/test/browser/editorTestServices.ts @@ -25,7 +25,7 @@ export class TestCodeEditorService extends AbstractCodeEditorService { } export class TestCommandService implements ICommandService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _instantiationService: IInstantiationService; diff --git a/src/vs/editor/test/browser/services/openerService.test.ts b/src/vs/editor/test/browser/services/openerService.test.ts index da6c8a38d4..b1a2c5751a 100644 --- a/src/vs/editor/test/browser/services/openerService.test.ts +++ b/src/vs/editor/test/browser/services/openerService.test.ts @@ -14,7 +14,7 @@ suite('OpenerService', function () { let lastCommand: { id: string; args: any[] } | undefined; const commandService = new (class implements ICommandService { - _serviceBrand: any; + _serviceBrand: undefined; onWillExecuteCommand = () => ({ dispose: () => { } }); onDidExecuteCommand = () => ({ dispose: () => { } }); executeCommand(id: string, ...args: any[]): Promise { diff --git a/src/vs/editor/test/browser/testCodeEditor.ts b/src/vs/editor/test/browser/testCodeEditor.ts index 70a7a734d6..fba696bf76 100644 --- a/src/vs/editor/test/browser/testCodeEditor.ts +++ b/src/vs/editor/test/browser/testCodeEditor.ts @@ -91,7 +91,12 @@ export function withTestCodeEditor(text: string | string[] | null, options: Test export function createTestCodeEditor(options: TestCodeEditorCreationOptions): TestCodeEditor { + const model = options.model; + delete options.model; + const services: ServiceCollection = options.serviceCollection || new ServiceCollection(); + delete options.serviceCollection; + const instantiationService: IInstantiationService = new InstantiationService(services); if (!services.has(ICodeEditorService)) { @@ -119,6 +124,6 @@ export function createTestCodeEditor(options: TestCodeEditorCreationOptions): Te options, codeEditorWidgetOptions ); - editor.setModel(options.model); + editor.setModel(model); return editor; } diff --git a/src/vs/editor/test/common/config/commonEditorConfig.test.ts b/src/vs/editor/test/common/config/commonEditorConfig.test.ts index a6ff4ca63d..e36b4b8e8d 100644 --- a/src/vs/editor/test/common/config/commonEditorConfig.test.ts +++ b/src/vs/editor/test/common/config/commonEditorConfig.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig'; -import { IEditorHoverOptions } from 'vs/editor/common/config/editorOptions'; +import { IEditorHoverOptions, EditorOption, ConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; import { EditorZoom } from 'vs/editor/common/config/editorZoom'; import { TestConfiguration } from 'vs/editor/test/common/mocks/testConfiguration'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; @@ -67,8 +67,10 @@ suite('Common Editor Config', () => { } function assertWrapping(config: TestConfiguration, isViewportWrapping: boolean, wrappingColumn: number): void { - assert.equal(config.editor.wrappingInfo.isViewportWrapping, isViewportWrapping); - assert.equal(config.editor.wrappingInfo.wrappingColumn, wrappingColumn); + const options = config.options; + const wrappingInfo = options.get(EditorOption.wrappingInfo); + assert.equal(wrappingInfo.isViewportWrapping, isViewportWrapping); + assert.equal(wrappingInfo.wrappingColumn, wrappingColumn); } test('wordWrap default', () => { @@ -184,8 +186,19 @@ suite('Common Editor Config', () => { }); let config = new TestConfiguration({ hover: hoverOptions }); - assert.equal(config.editor.contribInfo.hover.enabled, true); + assert.equal(config.options.get(EditorOption.hover).enabled, true); config.updateOptions({ hover: { enabled: false } }); - assert.equal(config.editor.contribInfo.hover.enabled, false); + assert.equal(config.options.get(EditorOption.hover).enabled, false); + }); + + test('does not emit event when nothing changes', () => { + const config = new TestConfiguration({ glyphMargin: true, roundedSelection: false }); + let event: ConfigurationChangedEvent | null = null; + config.onDidChange(e => event = e); + assert.equal(config.options.get(EditorOption.glyphMargin), true); + + config.updateOptions({ glyphMargin: true }); + config.updateOptions({ roundedSelection: false }); + assert.equal(event, null); }); }); diff --git a/src/vs/editor/test/common/model/linesTextBuffer/linesTextBuffer.test.ts b/src/vs/editor/test/common/model/linesTextBuffer/linesTextBuffer.test.ts index 13b1cda9ce..682025288b 100644 --- a/src/vs/editor/test/common/model/linesTextBuffer/linesTextBuffer.test.ts +++ b/src/vs/editor/test/common/model/linesTextBuffer/linesTextBuffer.test.ts @@ -306,10 +306,10 @@ suite('PieceTreeTextBuffer._toSingleEditOperation', () => { '', '1' ], [ - editOp(1, 1, 1, 3, 0, 2, ['Your']), - editOp(1, 4, 1, 4, 3, 0, ['Interesting ']), - editOp(2, 3, 2, 6, 16, 3, null) - ], + editOp(1, 1, 1, 3, 0, 2, ['Your']), + editOp(1, 4, 1, 4, 3, 0, ['Interesting ']), + editOp(2, 3, 2, 6, 16, 3, null) + ], editOp(1, 1, 2, 6, 0, 19, [ 'Your Interesting First Line', '\t\t' diff --git a/src/vs/editor/test/common/model/modelDecorations.test.ts b/src/vs/editor/test/common/model/modelDecorations.test.ts index e8b7ecf6f6..2cac668ebf 100644 --- a/src/vs/editor/test/common/model/modelDecorations.test.ts +++ b/src/vs/editor/test/common/model/modelDecorations.test.ts @@ -1312,8 +1312,8 @@ suite('deltaDecorations', () => { endLineNumber: 1, endColumn: 1 }, { - stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges - } + stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges + } ); }); model.changeDecorations((changeAccessor) => { diff --git a/src/vs/editor/test/common/model/textModelSearch.test.ts b/src/vs/editor/test/common/model/textModelSearch.test.ts index c9f79b5997..d21546e1fb 100644 --- a/src/vs/editor/test/common/model/textModelSearch.test.ts +++ b/src/vs/editor/test/common/model/textModelSearch.test.ts @@ -611,25 +611,25 @@ suite('TextModelSearch', () => { }); test('parseSearchRequest non regex', () => { - assertParseSearchResult('foo', false, false, null, new SearchData(/foo/gi, null, null)); - assertParseSearchResult('foo', false, false, USUAL_WORD_SEPARATORS, new SearchData(/foo/gi, usualWordSeparators, null)); - assertParseSearchResult('foo', false, true, null, new SearchData(/foo/g, null, 'foo')); - assertParseSearchResult('foo', false, true, USUAL_WORD_SEPARATORS, new SearchData(/foo/g, usualWordSeparators, 'foo')); - assertParseSearchResult('foo\\n', false, false, null, new SearchData(/foo\\n/gi, null, null)); - assertParseSearchResult('foo\\\\n', false, false, null, new SearchData(/foo\\\\n/gi, null, null)); - assertParseSearchResult('foo\\r', false, false, null, new SearchData(/foo\\r/gi, null, null)); - assertParseSearchResult('foo\\\\r', false, false, null, new SearchData(/foo\\\\r/gi, null, null)); + assertParseSearchResult('foo', false, false, null, new SearchData(/foo/giu, null, null)); + assertParseSearchResult('foo', false, false, USUAL_WORD_SEPARATORS, new SearchData(/foo/giu, usualWordSeparators, null)); + assertParseSearchResult('foo', false, true, null, new SearchData(/foo/gu, null, 'foo')); + assertParseSearchResult('foo', false, true, USUAL_WORD_SEPARATORS, new SearchData(/foo/gu, usualWordSeparators, 'foo')); + assertParseSearchResult('foo\\n', false, false, null, new SearchData(/foo\\n/giu, null, null)); + assertParseSearchResult('foo\\\\n', false, false, null, new SearchData(/foo\\\\n/giu, null, null)); + assertParseSearchResult('foo\\r', false, false, null, new SearchData(/foo\\r/giu, null, null)); + assertParseSearchResult('foo\\\\r', false, false, null, new SearchData(/foo\\\\r/giu, null, null)); }); test('parseSearchRequest regex', () => { - assertParseSearchResult('foo', true, false, null, new SearchData(/foo/gi, null, null)); - assertParseSearchResult('foo', true, false, USUAL_WORD_SEPARATORS, new SearchData(/foo/gi, usualWordSeparators, null)); - assertParseSearchResult('foo', true, true, null, new SearchData(/foo/g, null, null)); - assertParseSearchResult('foo', true, true, USUAL_WORD_SEPARATORS, new SearchData(/foo/g, usualWordSeparators, null)); - assertParseSearchResult('foo\\n', true, false, null, new SearchData(/foo\n/gim, null, null)); - assertParseSearchResult('foo\\\\n', true, false, null, new SearchData(/foo\\n/gi, null, null)); - assertParseSearchResult('foo\\r', true, false, null, new SearchData(/foo\r/gim, null, null)); - assertParseSearchResult('foo\\\\r', true, false, null, new SearchData(/foo\\r/gi, null, null)); + assertParseSearchResult('foo', true, false, null, new SearchData(/foo/giu, null, null)); + assertParseSearchResult('foo', true, false, USUAL_WORD_SEPARATORS, new SearchData(/foo/giu, usualWordSeparators, null)); + assertParseSearchResult('foo', true, true, null, new SearchData(/foo/gu, null, null)); + assertParseSearchResult('foo', true, true, USUAL_WORD_SEPARATORS, new SearchData(/foo/gu, usualWordSeparators, null)); + assertParseSearchResult('foo\\n', true, false, null, new SearchData(/foo\n/gimu, null, null)); + assertParseSearchResult('foo\\\\n', true, false, null, new SearchData(/foo\\n/giu, null, null)); + assertParseSearchResult('foo\\r', true, false, null, new SearchData(/foo\r/gimu, null, null)); + assertParseSearchResult('foo\\\\r', true, false, null, new SearchData(/foo\\r/giu, null, null)); }); test('issue #53415. \W should match line break.', () => { @@ -721,6 +721,20 @@ suite('TextModelSearch', () => { ); }); + test('Simple find using unicode escape sequences', () => { + assertFindMatches( + regularText.join('\n'), + '\\u{0066}\\u006f\\u006F', true, false, null, + [ + [1, 14, 1, 17], + [1, 44, 1, 47], + [2, 22, 2, 25], + [2, 48, 2, 51], + [4, 59, 4, 62] + ] + ); + }); + test('isMultilineRegexSource', () => { assert(!isMultilineRegexSource('foo')); assert(!isMultilineRegexSource('')); diff --git a/src/vs/editor/test/common/model/textModelWithTokens.test.ts b/src/vs/editor/test/common/model/textModelWithTokens.test.ts index 26bf194c18..0b7385be1b 100644 --- a/src/vs/editor/test/common/model/textModelWithTokens.test.ts +++ b/src/vs/editor/test/common/model/textModelWithTokens.test.ts @@ -138,10 +138,10 @@ suite('TextModelWithTokens', () => { testBrackets([ 'if (a == 3) { return (7 * (a + 5)); }' ], [ - ['{', '}'], - ['[', ']'], - ['(', ')'] - ]); + ['{', '}'], + ['[', ']'], + ['(', ')'] + ]); }); }); diff --git a/src/vs/editor/test/common/modes/supports/tokenization.test.ts b/src/vs/editor/test/common/modes/supports/tokenization.test.ts index 257f80570e..f96f1ada2e 100644 --- a/src/vs/editor/test/common/modes/supports/tokenization.test.ts +++ b/src/vs/editor/test/common/modes/supports/tokenization.test.ts @@ -334,8 +334,8 @@ suite('Token theme resolving', () => { let actual = TokenTheme.createFromParsedTokenTheme([ new ParsedTokenThemeRule('var', -1, FontStyle.NotSet, 'F8F8F2', null) ], [ - '000000', 'FFFFFF', '0F0F0F' - ]); + '000000', 'FFFFFF', '0F0F0F' + ]); let colorMap = new ColorMap(); colorMap.getId('000000'); colorMap.getId('FFFFFF'); diff --git a/src/vs/editor/test/common/services/modelService.test.ts b/src/vs/editor/test/common/services/modelService.test.ts index d1c5712dd4..fb9552df29 100644 --- a/src/vs/editor/test/common/services/modelService.test.ts +++ b/src/vs/editor/test/common/services/modelService.test.ts @@ -367,7 +367,7 @@ assertComputeEdits(file1, file2); class TestTextResourcePropertiesService implements ITextResourcePropertiesService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @IConfigurationService private readonly configurationService: IConfigurationService, diff --git a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts index 5dbdc2fbdb..9ced04b91a 100644 --- a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts +++ b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts @@ -4,12 +4,82 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { EditorLayoutInfo, EditorLayoutProvider, IEditorLayoutProviderOpts, RenderMinimap } from 'vs/editor/common/config/editorOptions'; +import { EditorLayoutInfo, EditorLayoutInfoComputer, RenderMinimap, EditorOption, EditorMinimapOptions, InternalEditorScrollbarOptions, EditorOptions, RenderLineNumbersType, InternalEditorRenderLineNumbersOptions } from 'vs/editor/common/config/editorOptions'; +import { ComputedEditorOptions } from 'vs/editor/common/config/commonEditorConfig'; + +interface IEditorLayoutProviderOpts { + readonly outerWidth: number; + readonly outerHeight: number; + + readonly showGlyphMargin: boolean; + readonly lineHeight: number; + + readonly showLineNumbers: boolean; + readonly lineNumbersMinChars: number; + readonly lineNumbersDigitCount: number; + + readonly lineDecorationsWidth: number; + + readonly typicalHalfwidthCharacterWidth: number; + readonly maxDigitWidth: number; + + readonly verticalScrollbarWidth: number; + readonly verticalScrollbarHasArrows: boolean; + readonly scrollbarArrowSize: number; + readonly horizontalScrollbarHeight: number; + + readonly minimap: boolean; + readonly minimapSide: 'left' | 'right'; + readonly minimapRenderCharacters: boolean; + readonly minimapMaxColumn: number; + readonly pixelRatio: number; +} suite('Editor ViewLayout - EditorLayoutProvider', () => { function doTest(input: IEditorLayoutProviderOpts, expected: EditorLayoutInfo): void { - let actual = EditorLayoutProvider.compute(input); + const options = new ComputedEditorOptions(); + options._write(EditorOption.glyphMargin, input.showGlyphMargin); + options._write(EditorOption.lineNumbersMinChars, input.lineNumbersMinChars); + options._write(EditorOption.lineDecorationsWidth, input.lineDecorationsWidth); + options._write(EditorOption.folding, false); + const minimapOptions: EditorMinimapOptions = { + enabled: input.minimap, + side: input.minimapSide, + renderCharacters: input.minimapRenderCharacters, + maxColumn: input.minimapMaxColumn, + showSlider: 'mouseover' + }; + options._write(EditorOption.minimap, minimapOptions); + const scrollbarOptions: InternalEditorScrollbarOptions = { + arrowSize: input.scrollbarArrowSize, + vertical: EditorOptions.scrollbar.defaultValue.vertical, + horizontal: EditorOptions.scrollbar.defaultValue.horizontal, + useShadows: EditorOptions.scrollbar.defaultValue.useShadows, + verticalHasArrows: input.verticalScrollbarHasArrows, + horizontalHasArrows: false, + handleMouseWheel: EditorOptions.scrollbar.defaultValue.handleMouseWheel, + horizontalScrollbarSize: input.horizontalScrollbarHeight, + horizontalSliderSize: EditorOptions.scrollbar.defaultValue.horizontalSliderSize, + verticalScrollbarSize: input.verticalScrollbarWidth, + verticalSliderSize: EditorOptions.scrollbar.defaultValue.verticalSliderSize, + }; + options._write(EditorOption.scrollbar, scrollbarOptions); + const lineNumbersOptions: InternalEditorRenderLineNumbersOptions = { + renderType: input.showLineNumbers ? RenderLineNumbersType.On : RenderLineNumbersType.Off, + renderFn: null + }; + options._write(EditorOption.lineNumbers, lineNumbersOptions); + + const actual = EditorLayoutInfoComputer.computeLayout(options, { + outerWidth: input.outerWidth, + outerHeight: input.outerHeight, + lineHeight: input.lineHeight, + lineNumbersDigitCount: input.lineNumbersDigitCount, + typicalHalfwidthCharacterWidth: input.typicalHalfwidthCharacterWidth, + maxDigitWidth: input.maxDigitWidth, + pixelRatio: input.pixelRatio, + }); assert.deepEqual(actual, expected); } @@ -35,40 +105,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 150, pixelRatio: 1, }, { - width: 1000, + width: 1000, + height: 800, + + glyphMarginLeft: 0, + glyphMarginWidth: 0, + glyphMarginHeight: 800, + + lineNumbersLeft: 0, + lineNumbersWidth: 0, + lineNumbersHeight: 800, + + decorationsLeft: 0, + decorationsWidth: 10, + decorationsHeight: 800, + + contentLeft: 10, + contentWidth: 990, + contentHeight: 800, + + renderMinimap: RenderMinimap.None, + minimapLeft: 0, + minimapWidth: 0, + viewportColumn: 98, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, height: 800, - - glyphMarginLeft: 0, - glyphMarginWidth: 0, - glyphMarginHeight: 800, - - lineNumbersLeft: 0, - lineNumbersWidth: 0, - lineNumbersHeight: 800, - - decorationsLeft: 0, - decorationsWidth: 10, - decorationsHeight: 800, - - contentLeft: 10, - contentWidth: 990, - contentHeight: 800, - - renderMinimap: RenderMinimap.None, - minimapLeft: 0, - minimapWidth: 0, - viewportColumn: 98, - - verticalScrollbarWidth: 0, - horizontalScrollbarHeight: 0, - - overviewRuler: { - top: 0, - width: 0, - height: 800, - right: 0 - } - }); + right: 0 + } + }); }); test('EditorLayoutProvider 1.1', () => { @@ -93,40 +163,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 150, pixelRatio: 1, }, { - width: 1000, - height: 800, + width: 1000, + height: 800, - glyphMarginLeft: 0, - glyphMarginWidth: 0, - glyphMarginHeight: 800, + glyphMarginLeft: 0, + glyphMarginWidth: 0, + glyphMarginHeight: 800, - lineNumbersLeft: 0, - lineNumbersWidth: 0, - lineNumbersHeight: 800, + lineNumbersLeft: 0, + lineNumbersWidth: 0, + lineNumbersHeight: 800, - decorationsLeft: 0, - decorationsWidth: 10, - decorationsHeight: 800, + decorationsLeft: 0, + decorationsWidth: 10, + decorationsHeight: 800, - contentLeft: 10, - contentWidth: 990, - contentHeight: 800, + contentLeft: 10, + contentWidth: 990, + contentHeight: 800, - renderMinimap: RenderMinimap.None, - minimapLeft: 0, - minimapWidth: 0, - viewportColumn: 97, + renderMinimap: RenderMinimap.None, + minimapLeft: 0, + minimapWidth: 0, + viewportColumn: 97, - verticalScrollbarWidth: 11, - horizontalScrollbarHeight: 12, + verticalScrollbarWidth: 11, + horizontalScrollbarHeight: 12, - overviewRuler: { - top: 13, - width: 11, - height: (800 - 2 * 13), - right: 0 - } - }); + overviewRuler: { + top: 13, + width: 11, + height: (800 - 2 * 13), + right: 0 + } + }); }); test('EditorLayoutProvider 2', () => { @@ -151,40 +221,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 150, pixelRatio: 1, }, { - width: 900, + width: 900, + height: 800, + + glyphMarginLeft: 0, + glyphMarginWidth: 0, + glyphMarginHeight: 800, + + lineNumbersLeft: 0, + lineNumbersWidth: 0, + lineNumbersHeight: 800, + + decorationsLeft: 0, + decorationsWidth: 10, + decorationsHeight: 800, + + contentLeft: 10, + contentWidth: 890, + contentHeight: 800, + + renderMinimap: RenderMinimap.None, + minimapLeft: 0, + minimapWidth: 0, + viewportColumn: 88, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, height: 800, - - glyphMarginLeft: 0, - glyphMarginWidth: 0, - glyphMarginHeight: 800, - - lineNumbersLeft: 0, - lineNumbersWidth: 0, - lineNumbersHeight: 800, - - decorationsLeft: 0, - decorationsWidth: 10, - decorationsHeight: 800, - - contentLeft: 10, - contentWidth: 890, - contentHeight: 800, - - renderMinimap: RenderMinimap.None, - minimapLeft: 0, - minimapWidth: 0, - viewportColumn: 88, - - verticalScrollbarWidth: 0, - horizontalScrollbarHeight: 0, - - overviewRuler: { - top: 0, - width: 0, - height: 800, - right: 0 - } - }); + right: 0 + } + }); }); test('EditorLayoutProvider 3', () => { @@ -209,40 +279,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 150, pixelRatio: 1, }, { - width: 900, + width: 900, + height: 900, + + glyphMarginLeft: 0, + glyphMarginWidth: 0, + glyphMarginHeight: 900, + + lineNumbersLeft: 0, + lineNumbersWidth: 0, + lineNumbersHeight: 900, + + decorationsLeft: 0, + decorationsWidth: 10, + decorationsHeight: 900, + + contentLeft: 10, + contentWidth: 890, + contentHeight: 900, + + renderMinimap: RenderMinimap.None, + minimapLeft: 0, + minimapWidth: 0, + viewportColumn: 88, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, height: 900, - - glyphMarginLeft: 0, - glyphMarginWidth: 0, - glyphMarginHeight: 900, - - lineNumbersLeft: 0, - lineNumbersWidth: 0, - lineNumbersHeight: 900, - - decorationsLeft: 0, - decorationsWidth: 10, - decorationsHeight: 900, - - contentLeft: 10, - contentWidth: 890, - contentHeight: 900, - - renderMinimap: RenderMinimap.None, - minimapLeft: 0, - minimapWidth: 0, - viewportColumn: 88, - - verticalScrollbarWidth: 0, - horizontalScrollbarHeight: 0, - - overviewRuler: { - top: 0, - width: 0, - height: 900, - right: 0 - } - }); + right: 0 + } + }); }); test('EditorLayoutProvider 4', () => { @@ -267,40 +337,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 150, pixelRatio: 1, }, { - width: 900, + width: 900, + height: 900, + + glyphMarginLeft: 0, + glyphMarginWidth: 0, + glyphMarginHeight: 900, + + lineNumbersLeft: 0, + lineNumbersWidth: 0, + lineNumbersHeight: 900, + + decorationsLeft: 0, + decorationsWidth: 10, + decorationsHeight: 900, + + contentLeft: 10, + contentWidth: 890, + contentHeight: 900, + + renderMinimap: RenderMinimap.None, + minimapLeft: 0, + minimapWidth: 0, + viewportColumn: 88, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, height: 900, - - glyphMarginLeft: 0, - glyphMarginWidth: 0, - glyphMarginHeight: 900, - - lineNumbersLeft: 0, - lineNumbersWidth: 0, - lineNumbersHeight: 900, - - decorationsLeft: 0, - decorationsWidth: 10, - decorationsHeight: 900, - - contentLeft: 10, - contentWidth: 890, - contentHeight: 900, - - renderMinimap: RenderMinimap.None, - minimapLeft: 0, - minimapWidth: 0, - viewportColumn: 88, - - verticalScrollbarWidth: 0, - horizontalScrollbarHeight: 0, - - overviewRuler: { - top: 0, - width: 0, - height: 900, - right: 0 - } - }); + right: 0 + } + }); }); test('EditorLayoutProvider 5', () => { @@ -325,40 +395,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 150, pixelRatio: 1, }, { - width: 900, + width: 900, + height: 900, + + glyphMarginLeft: 0, + glyphMarginWidth: 0, + glyphMarginHeight: 900, + + lineNumbersLeft: 0, + lineNumbersWidth: 50, + lineNumbersHeight: 900, + + decorationsLeft: 50, + decorationsWidth: 10, + decorationsHeight: 900, + + contentLeft: 60, + contentWidth: 840, + contentHeight: 900, + + renderMinimap: RenderMinimap.None, + minimapLeft: 0, + minimapWidth: 0, + viewportColumn: 83, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, height: 900, - - glyphMarginLeft: 0, - glyphMarginWidth: 0, - glyphMarginHeight: 900, - - lineNumbersLeft: 0, - lineNumbersWidth: 50, - lineNumbersHeight: 900, - - decorationsLeft: 50, - decorationsWidth: 10, - decorationsHeight: 900, - - contentLeft: 60, - contentWidth: 840, - contentHeight: 900, - - renderMinimap: RenderMinimap.None, - minimapLeft: 0, - minimapWidth: 0, - viewportColumn: 83, - - verticalScrollbarWidth: 0, - horizontalScrollbarHeight: 0, - - overviewRuler: { - top: 0, - width: 0, - height: 900, - right: 0 - } - }); + right: 0 + } + }); }); test('EditorLayoutProvider 6', () => { @@ -383,40 +453,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 150, pixelRatio: 1, }, { - width: 900, + width: 900, + height: 900, + + glyphMarginLeft: 0, + glyphMarginWidth: 0, + glyphMarginHeight: 900, + + lineNumbersLeft: 0, + lineNumbersWidth: 50, + lineNumbersHeight: 900, + + decorationsLeft: 50, + decorationsWidth: 10, + decorationsHeight: 900, + + contentLeft: 60, + contentWidth: 840, + contentHeight: 900, + + renderMinimap: RenderMinimap.None, + minimapLeft: 0, + minimapWidth: 0, + viewportColumn: 83, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, height: 900, - - glyphMarginLeft: 0, - glyphMarginWidth: 0, - glyphMarginHeight: 900, - - lineNumbersLeft: 0, - lineNumbersWidth: 50, - lineNumbersHeight: 900, - - decorationsLeft: 50, - decorationsWidth: 10, - decorationsHeight: 900, - - contentLeft: 60, - contentWidth: 840, - contentHeight: 900, - - renderMinimap: RenderMinimap.None, - minimapLeft: 0, - minimapWidth: 0, - viewportColumn: 83, - - verticalScrollbarWidth: 0, - horizontalScrollbarHeight: 0, - - overviewRuler: { - top: 0, - width: 0, - height: 900, - right: 0 - } - }); + right: 0 + } + }); }); test('EditorLayoutProvider 7', () => { @@ -441,40 +511,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 150, pixelRatio: 1, }, { - width: 900, + width: 900, + height: 900, + + glyphMarginLeft: 0, + glyphMarginWidth: 0, + glyphMarginHeight: 900, + + lineNumbersLeft: 0, + lineNumbersWidth: 60, + lineNumbersHeight: 900, + + decorationsLeft: 60, + decorationsWidth: 10, + decorationsHeight: 900, + + contentLeft: 70, + contentWidth: 830, + contentHeight: 900, + + renderMinimap: RenderMinimap.None, + minimapLeft: 0, + minimapWidth: 0, + viewportColumn: 82, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, height: 900, - - glyphMarginLeft: 0, - glyphMarginWidth: 0, - glyphMarginHeight: 900, - - lineNumbersLeft: 0, - lineNumbersWidth: 60, - lineNumbersHeight: 900, - - decorationsLeft: 60, - decorationsWidth: 10, - decorationsHeight: 900, - - contentLeft: 70, - contentWidth: 830, - contentHeight: 900, - - renderMinimap: RenderMinimap.None, - minimapLeft: 0, - minimapWidth: 0, - viewportColumn: 82, - - verticalScrollbarWidth: 0, - horizontalScrollbarHeight: 0, - - overviewRuler: { - top: 0, - width: 0, - height: 900, - right: 0 - } - }); + right: 0 + } + }); }); test('EditorLayoutProvider 8', () => { @@ -499,40 +569,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 150, pixelRatio: 1, }, { - width: 900, + width: 900, + height: 900, + + glyphMarginLeft: 0, + glyphMarginWidth: 0, + glyphMarginHeight: 900, + + lineNumbersLeft: 0, + lineNumbersWidth: 30, + lineNumbersHeight: 900, + + decorationsLeft: 30, + decorationsWidth: 10, + decorationsHeight: 900, + + contentLeft: 40, + contentWidth: 860, + contentHeight: 900, + + renderMinimap: RenderMinimap.None, + minimapLeft: 0, + minimapWidth: 0, + viewportColumn: 171, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, height: 900, - - glyphMarginLeft: 0, - glyphMarginWidth: 0, - glyphMarginHeight: 900, - - lineNumbersLeft: 0, - lineNumbersWidth: 30, - lineNumbersHeight: 900, - - decorationsLeft: 30, - decorationsWidth: 10, - decorationsHeight: 900, - - contentLeft: 40, - contentWidth: 860, - contentHeight: 900, - - renderMinimap: RenderMinimap.None, - minimapLeft: 0, - minimapWidth: 0, - viewportColumn: 171, - - verticalScrollbarWidth: 0, - horizontalScrollbarHeight: 0, - - overviewRuler: { - top: 0, - width: 0, - height: 900, - right: 0 - } - }); + right: 0 + } + }); }); test('EditorLayoutProvider 8 - rounds floats', () => { @@ -557,40 +627,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 150, pixelRatio: 1, }, { - width: 900, + width: 900, + height: 900, + + glyphMarginLeft: 0, + glyphMarginWidth: 0, + glyphMarginHeight: 900, + + lineNumbersLeft: 0, + lineNumbersWidth: 30, + lineNumbersHeight: 900, + + decorationsLeft: 30, + decorationsWidth: 10, + decorationsHeight: 900, + + contentLeft: 40, + contentWidth: 860, + contentHeight: 900, + + renderMinimap: RenderMinimap.None, + minimapLeft: 0, + minimapWidth: 0, + viewportColumn: 169, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, height: 900, - - glyphMarginLeft: 0, - glyphMarginWidth: 0, - glyphMarginHeight: 900, - - lineNumbersLeft: 0, - lineNumbersWidth: 30, - lineNumbersHeight: 900, - - decorationsLeft: 30, - decorationsWidth: 10, - decorationsHeight: 900, - - contentLeft: 40, - contentWidth: 860, - contentHeight: 900, - - renderMinimap: RenderMinimap.None, - minimapLeft: 0, - minimapWidth: 0, - viewportColumn: 169, - - verticalScrollbarWidth: 0, - horizontalScrollbarHeight: 0, - - overviewRuler: { - top: 0, - width: 0, - height: 900, - right: 0 - } - }); + right: 0 + } + }); }); test('EditorLayoutProvider 9 - render minimap', () => { @@ -615,40 +685,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 150, pixelRatio: 1, }, { - width: 1000, + width: 1000, + height: 800, + + glyphMarginLeft: 0, + glyphMarginWidth: 0, + glyphMarginHeight: 800, + + lineNumbersLeft: 0, + lineNumbersWidth: 0, + lineNumbersHeight: 800, + + decorationsLeft: 0, + decorationsWidth: 10, + decorationsHeight: 800, + + contentLeft: 10, + contentWidth: 901, + contentHeight: 800, + + renderMinimap: RenderMinimap.Small, + minimapLeft: 911, + minimapWidth: 89, + viewportColumn: 89, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, height: 800, - - glyphMarginLeft: 0, - glyphMarginWidth: 0, - glyphMarginHeight: 800, - - lineNumbersLeft: 0, - lineNumbersWidth: 0, - lineNumbersHeight: 800, - - decorationsLeft: 0, - decorationsWidth: 10, - decorationsHeight: 800, - - contentLeft: 10, - contentWidth: 901, - contentHeight: 800, - - renderMinimap: RenderMinimap.Small, - minimapLeft: 911, - minimapWidth: 89, - viewportColumn: 89, - - verticalScrollbarWidth: 0, - horizontalScrollbarHeight: 0, - - overviewRuler: { - top: 0, - width: 0, - height: 800, - right: 0 - } - }); + right: 0 + } + }); }); test('EditorLayoutProvider 9 - render minimap with pixelRatio = 2', () => { @@ -673,40 +743,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 150, pixelRatio: 2, }, { - width: 1000, + width: 1000, + height: 800, + + glyphMarginLeft: 0, + glyphMarginWidth: 0, + glyphMarginHeight: 800, + + lineNumbersLeft: 0, + lineNumbersWidth: 0, + lineNumbersHeight: 800, + + decorationsLeft: 0, + decorationsWidth: 10, + decorationsHeight: 800, + + contentLeft: 10, + contentWidth: 901, + contentHeight: 800, + + renderMinimap: RenderMinimap.Large, + minimapLeft: 911, + minimapWidth: 89, + viewportColumn: 89, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, height: 800, - - glyphMarginLeft: 0, - glyphMarginWidth: 0, - glyphMarginHeight: 800, - - lineNumbersLeft: 0, - lineNumbersWidth: 0, - lineNumbersHeight: 800, - - decorationsLeft: 0, - decorationsWidth: 10, - decorationsHeight: 800, - - contentLeft: 10, - contentWidth: 901, - contentHeight: 800, - - renderMinimap: RenderMinimap.Large, - minimapLeft: 911, - minimapWidth: 89, - viewportColumn: 89, - - verticalScrollbarWidth: 0, - horizontalScrollbarHeight: 0, - - overviewRuler: { - top: 0, - width: 0, - height: 800, - right: 0 - } - }); + right: 0 + } + }); }); test('EditorLayoutProvider 9 - render minimap with pixelRatio = 4', () => { @@ -731,40 +801,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 150, pixelRatio: 4, }, { - width: 1000, + width: 1000, + height: 800, + + glyphMarginLeft: 0, + glyphMarginWidth: 0, + glyphMarginHeight: 800, + + lineNumbersLeft: 0, + lineNumbersWidth: 0, + lineNumbersHeight: 800, + + decorationsLeft: 0, + decorationsWidth: 10, + decorationsHeight: 800, + + contentLeft: 10, + contentWidth: 943, + contentHeight: 800, + + renderMinimap: RenderMinimap.Large, + minimapLeft: 953, + minimapWidth: 47, + viewportColumn: 94, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, height: 800, - - glyphMarginLeft: 0, - glyphMarginWidth: 0, - glyphMarginHeight: 800, - - lineNumbersLeft: 0, - lineNumbersWidth: 0, - lineNumbersHeight: 800, - - decorationsLeft: 0, - decorationsWidth: 10, - decorationsHeight: 800, - - contentLeft: 10, - contentWidth: 943, - contentHeight: 800, - - renderMinimap: RenderMinimap.Large, - minimapLeft: 953, - minimapWidth: 47, - viewportColumn: 94, - - verticalScrollbarWidth: 0, - horizontalScrollbarHeight: 0, - - overviewRuler: { - top: 0, - width: 0, - height: 800, - right: 0 - } - }); + right: 0 + } + }); }); test('EditorLayoutProvider 10 - render minimap to left', () => { @@ -789,40 +859,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 150, pixelRatio: 4, }, { - width: 1000, + width: 1000, + height: 800, + + glyphMarginLeft: 47, + glyphMarginWidth: 0, + glyphMarginHeight: 800, + + lineNumbersLeft: 47, + lineNumbersWidth: 0, + lineNumbersHeight: 800, + + decorationsLeft: 47, + decorationsWidth: 10, + decorationsHeight: 800, + + contentLeft: 57, + contentWidth: 943, + contentHeight: 800, + + renderMinimap: RenderMinimap.Large, + minimapLeft: 0, + minimapWidth: 47, + viewportColumn: 94, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, height: 800, - - glyphMarginLeft: 47, - glyphMarginWidth: 0, - glyphMarginHeight: 800, - - lineNumbersLeft: 47, - lineNumbersWidth: 0, - lineNumbersHeight: 800, - - decorationsLeft: 47, - decorationsWidth: 10, - decorationsHeight: 800, - - contentLeft: 57, - contentWidth: 943, - contentHeight: 800, - - renderMinimap: RenderMinimap.Large, - minimapLeft: 0, - minimapWidth: 47, - viewportColumn: 94, - - verticalScrollbarWidth: 0, - horizontalScrollbarHeight: 0, - - overviewRuler: { - top: 0, - width: 0, - height: 800, - right: 0 - } - }); + right: 0 + } + }); }); test('issue #31312: When wrapping, leave 2px for the cursor', () => { @@ -847,40 +917,40 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapMaxColumn: 120, pixelRatio: 2 }, { - width: 1201, + width: 1201, + height: 422, + + glyphMarginLeft: 0, + glyphMarginWidth: 30, + glyphMarginHeight: 422, + + lineNumbersLeft: 30, + lineNumbersWidth: 36, + lineNumbersHeight: 422, + + decorationsLeft: 66, + decorationsWidth: 26, + decorationsHeight: 422, + + contentLeft: 92, + contentWidth: 1026, + contentHeight: 422, + + renderMinimap: RenderMinimap.Large, + minimapLeft: 1104, + minimapWidth: 83, + viewportColumn: 83, + + verticalScrollbarWidth: 14, + horizontalScrollbarHeight: 10, + + overviewRuler: { + top: 0, + width: 14, height: 422, - - glyphMarginLeft: 0, - glyphMarginWidth: 30, - glyphMarginHeight: 422, - - lineNumbersLeft: 30, - lineNumbersWidth: 36, - lineNumbersHeight: 422, - - decorationsLeft: 66, - decorationsWidth: 26, - decorationsHeight: 422, - - contentLeft: 92, - contentWidth: 1026, - contentHeight: 422, - - renderMinimap: RenderMinimap.Large, - minimapLeft: 1104, - minimapWidth: 83, - viewportColumn: 83, - - verticalScrollbarWidth: 14, - horizontalScrollbarHeight: 10, - - overviewRuler: { - top: 0, - width: 14, - height: 422, - right: 0 - } - }); + right: 0 + } + }); }); }); diff --git a/src/vs/editor/test/common/viewLayout/lineDecorations.test.ts b/src/vs/editor/test/common/viewLayout/lineDecorations.test.ts index aeb64c1646..af9727a048 100644 --- a/src/vs/editor/test/common/viewLayout/lineDecorations.test.ts +++ b/src/vs/editor/test/common/viewLayout/lineDecorations.test.ts @@ -66,34 +66,34 @@ suite('Editor ViewLayout - ViewLineParts', () => { new LineDecoration(1, 2, 'c1', InlineDecorationType.Regular), new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular) ]), [ - new DecorationSegment(0, 0, 'c1'), - new DecorationSegment(2, 2, 'c2') - ]); + new DecorationSegment(0, 0, 'c1'), + new DecorationSegment(2, 2, 'c2') + ]); assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(1, 3, 'c1', InlineDecorationType.Regular), new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular) ]), [ - new DecorationSegment(0, 1, 'c1'), - new DecorationSegment(2, 2, 'c2') - ]); + new DecorationSegment(0, 1, 'c1'), + new DecorationSegment(2, 2, 'c2') + ]); assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(1, 4, 'c1', InlineDecorationType.Regular), new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular) ]), [ - new DecorationSegment(0, 1, 'c1'), - new DecorationSegment(2, 2, 'c1 c2') - ]); + new DecorationSegment(0, 1, 'c1'), + new DecorationSegment(2, 2, 'c1 c2') + ]); assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(1, 4, 'c1', InlineDecorationType.Regular), new LineDecoration(1, 4, 'c1*', InlineDecorationType.Regular), new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular) ]), [ - new DecorationSegment(0, 1, 'c1 c1*'), - new DecorationSegment(2, 2, 'c1 c1* c2') - ]); + new DecorationSegment(0, 1, 'c1 c1*'), + new DecorationSegment(2, 2, 'c1 c1* c2') + ]); assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(1, 4, 'c1', InlineDecorationType.Regular), @@ -101,9 +101,9 @@ suite('Editor ViewLayout - ViewLineParts', () => { new LineDecoration(1, 4, 'c1**', InlineDecorationType.Regular), new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular) ]), [ - new DecorationSegment(0, 1, 'c1 c1* c1**'), - new DecorationSegment(2, 2, 'c1 c1* c1** c2') - ]); + new DecorationSegment(0, 1, 'c1 c1* c1**'), + new DecorationSegment(2, 2, 'c1 c1* c1** c2') + ]); assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(1, 4, 'c1', InlineDecorationType.Regular), @@ -112,9 +112,9 @@ suite('Editor ViewLayout - ViewLineParts', () => { new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular), new LineDecoration(3, 4, 'c2*', InlineDecorationType.Regular) ]), [ - new DecorationSegment(0, 1, 'c1 c1* c1**'), - new DecorationSegment(2, 2, 'c1 c1* c1** c2 c2*') - ]); + new DecorationSegment(0, 1, 'c1 c1* c1**'), + new DecorationSegment(2, 2, 'c1 c1* c1** c2 c2*') + ]); assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(1, 4, 'c1', InlineDecorationType.Regular), @@ -123,9 +123,9 @@ suite('Editor ViewLayout - ViewLineParts', () => { new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular), new LineDecoration(3, 5, 'c2*', InlineDecorationType.Regular) ]), [ - new DecorationSegment(0, 1, 'c1 c1* c1**'), - new DecorationSegment(2, 2, 'c1 c1* c1** c2 c2*'), - new DecorationSegment(3, 3, 'c2*') - ]); + new DecorationSegment(0, 1, 'c1 c1* c1**'), + new DecorationSegment(2, 2, 'c1 c1* c1** c2 c2*'), + new DecorationSegment(3, 3, 'c2*') + ]); }); }); diff --git a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts index 2744aecdac..66ad6fde93 100644 --- a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts +++ b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts @@ -19,6 +19,8 @@ import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer' import { ILineMapping, ISimpleModel, SplitLine, SplitLinesCollection } from 'vs/editor/common/viewModel/splitLinesCollection'; import { ViewLineData } from 'vs/editor/common/viewModel/viewModel'; import { TestConfiguration } from 'vs/editor/test/common/mocks/testConfiguration'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + suite('Editor ViewModel - SplitLinesCollection', () => { test('SplitLine', () => { @@ -88,15 +90,21 @@ suite('Editor ViewModel - SplitLinesCollection', () => { }); function withSplitLinesCollection(text: string, callback: (model: TextModel, linesCollection: SplitLinesCollection) => void): void { - let config = new TestConfiguration({}); + const config = new TestConfiguration({}); + const wrappingInfo = config.options.get(EditorOption.wrappingInfo); + const fontInfo = config.options.get(EditorOption.fontInfo); + const wordWrapBreakAfterCharacters = config.options.get(EditorOption.wordWrapBreakAfterCharacters); + const wordWrapBreakBeforeCharacters = config.options.get(EditorOption.wordWrapBreakBeforeCharacters); + const wordWrapBreakObtrusiveCharacters = config.options.get(EditorOption.wordWrapBreakObtrusiveCharacters); + const wrappingIndent = config.options.get(EditorOption.wrappingIndent); - let hardWrappingLineMapperFactory = new CharacterHardWrappingLineMapperFactory( - config.editor.wrappingInfo.wordWrapBreakBeforeCharacters, - config.editor.wrappingInfo.wordWrapBreakAfterCharacters, - config.editor.wrappingInfo.wordWrapBreakObtrusiveCharacters + const hardWrappingLineMapperFactory = new CharacterHardWrappingLineMapperFactory( + wordWrapBreakBeforeCharacters, + wordWrapBreakAfterCharacters, + wordWrapBreakObtrusiveCharacters ); - let model = TextModel.createFromString([ + const model = TextModel.createFromString([ 'int main() {', '\tprintf("Hello world!");', '}', @@ -105,13 +113,13 @@ suite('Editor ViewModel - SplitLinesCollection', () => { '}', ].join('\n')); - let linesCollection = new SplitLinesCollection( + const linesCollection = new SplitLinesCollection( model, hardWrappingLineMapperFactory, model.getOptions().tabSize, - config.editor.wrappingInfo.wrappingColumn, - config.editor.fontInfo.typicalFullwidthCharacterWidth / config.editor.fontInfo.typicalHalfwidthCharacterWidth, - config.editor.wrappingInfo.wrappingIndent + wrappingInfo.wrappingColumn, + fontInfo.typicalFullwidthCharacterWidth / fontInfo.typicalHalfwidthCharacterWidth, + wrappingIndent ); callback(model, linesCollection); @@ -732,25 +740,31 @@ suite('SplitLinesCollection', () => { }); function withSplitLinesCollection(model: TextModel, wordWrap: 'on' | 'off' | 'wordWrapColumn' | 'bounded', wordWrapColumn: number, callback: (splitLinesCollection: SplitLinesCollection) => void): void { - let configuration = new TestConfiguration({ + const configuration = new TestConfiguration({ wordWrap: wordWrap, wordWrapColumn: wordWrapColumn, wrappingIndent: 'indent' }); + const wrappingInfo = configuration.options.get(EditorOption.wrappingInfo); + const fontInfo = configuration.options.get(EditorOption.fontInfo); + const wordWrapBreakAfterCharacters = configuration.options.get(EditorOption.wordWrapBreakAfterCharacters); + const wordWrapBreakBeforeCharacters = configuration.options.get(EditorOption.wordWrapBreakBeforeCharacters); + const wordWrapBreakObtrusiveCharacters = configuration.options.get(EditorOption.wordWrapBreakObtrusiveCharacters); + const wrappingIndent = configuration.options.get(EditorOption.wrappingIndent); - let factory = new CharacterHardWrappingLineMapperFactory( - configuration.editor.wrappingInfo.wordWrapBreakBeforeCharacters, - configuration.editor.wrappingInfo.wordWrapBreakAfterCharacters, - configuration.editor.wrappingInfo.wordWrapBreakObtrusiveCharacters + const factory = new CharacterHardWrappingLineMapperFactory( + wordWrapBreakBeforeCharacters, + wordWrapBreakAfterCharacters, + wordWrapBreakObtrusiveCharacters ); - let linesCollection = new SplitLinesCollection( + const linesCollection = new SplitLinesCollection( model, factory, model.getOptions().tabSize, - configuration.editor.wrappingInfo.wrappingColumn, - configuration.editor.fontInfo.typicalFullwidthCharacterWidth / configuration.editor.fontInfo.typicalHalfwidthCharacterWidth, - configuration.editor.wrappingInfo.wrappingIndent + wrappingInfo.wrappingColumn, + fontInfo.typicalFullwidthCharacterWidth / fontInfo.typicalHalfwidthCharacterWidth, + wrappingIndent ); callback(linesCollection); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 8e1bace5eb..8ab1ed624e 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -2408,80 +2408,13 @@ declare namespace monaco.editor { readonly reason: CursorChangeReason; } - /** - * Configuration options for editor scrollbars - */ - export interface IEditorScrollbarOptions { + export enum AccessibilitySupport { /** - * The size of arrows (if displayed). - * Defaults to 11. + * This should be the browser case where it is not known if a screen reader is attached or no. */ - arrowSize?: number; - /** - * Render vertical scrollbar. - * Defaults to 'auto'. - */ - vertical?: 'auto' | 'visible' | 'hidden'; - /** - * Render horizontal scrollbar. - * Defaults to 'auto'. - */ - horizontal?: 'auto' | 'visible' | 'hidden'; - /** - * Cast horizontal and vertical shadows when the content is scrolled. - * Defaults to true. - */ - useShadows?: boolean; - /** - * Render arrows at the top and bottom of the vertical scrollbar. - * Defaults to false. - */ - verticalHasArrows?: boolean; - /** - * Render arrows at the left and right of the horizontal scrollbar. - * Defaults to false. - */ - horizontalHasArrows?: boolean; - /** - * Listen to mouse wheel events and react to them by scrolling. - * Defaults to true. - */ - handleMouseWheel?: boolean; - /** - * Height in pixels for the horizontal scrollbar. - * Defaults to 10 (px). - */ - horizontalScrollbarSize?: number; - /** - * Width in pixels for the vertical scrollbar. - * Defaults to 10 (px). - */ - verticalScrollbarSize?: number; - /** - * Width in pixels for the vertical slider. - * Defaults to `verticalScrollbarSize`. - */ - verticalSliderSize?: number; - /** - * Height in pixels for the horizontal slider. - * Defaults to `horizontalScrollbarSize`. - */ - horizontalSliderSize?: number; - } - - /** - * Configuration options for editor find widget - */ - export interface IEditorFindOptions { - /** - * Controls if we seed search string in the Find Widget with editor selection. - */ - seedSearchStringFromSelection?: boolean; - /** - * Controls if Find in Selection flag is turned on when multiple lines of text are selected in the editor. - */ - autoFindInSelection: boolean; - addExtraSpaceOnTop?: boolean; + Unknown = 0, + Disabled = 1, + Enabled = 2 } /** @@ -2499,134 +2432,14 @@ declare namespace monaco.editor { */ export type EditorAutoClosingOvertypeStrategy = 'always' | 'auto' | 'never'; - /** - * Configuration options for editor minimap - */ - export interface IEditorMinimapOptions { - /** - * Enable the rendering of the minimap. - * Defaults to true. - */ - enabled?: boolean; - /** - * Control the side of the minimap in editor. - * Defaults to 'right'. - */ - side?: 'right' | 'left'; - /** - * Control the rendering of the minimap slider. - * Defaults to 'mouseover'. - */ - showSlider?: 'always' | 'mouseover'; - /** - * Render the actual text on a line (as opposed to color blocks). - * Defaults to true. - */ - renderCharacters?: boolean; - /** - * Limit the width of the minimap to render at most a certain number of columns. - * Defaults to 120. - */ - maxColumn?: number; - } - - /** - * Configuration options for editor minimap - */ - export interface IEditorLightbulbOptions { - /** - * Enable the lightbulb code action. - * Defaults to true. - */ - enabled?: boolean; - } - - /** - * Configuration options for editor hover - */ - export interface IEditorHoverOptions { - /** - * Enable the hover. - * Defaults to true. - */ - enabled?: boolean; - /** - * Delay for showing the hover. - * Defaults to 300. - */ - delay?: number; - /** - * Is the hover sticky such that it can be clicked and its contents selected? - * Defaults to true. - */ - sticky?: boolean; - } - - /** - * Configuration options for parameter hints - */ - export interface IEditorParameterHintOptions { - /** - * Enable parameter hints. - * Defaults to true. - */ - enabled?: boolean; - /** - * Enable cycling of parameter hints. - * Defaults to false. - */ - cycle?: boolean; - } - - export interface ISuggestOptions { - /** - * Enable graceful matching. Defaults to true. - */ - filterGraceful?: boolean; - /** - * Prevent quick suggestions when a snippet is active. Defaults to true. - */ - snippetsPreventQuickSuggestions?: boolean; - /** - * Favours words that appear close to the cursor. - */ - localityBonus?: boolean; - /** - * Enable using global storage for remembering suggestions. - */ - shareSuggestSelections?: boolean; - /** - * Enable or disable icons in suggestions. Defaults to true. - */ - showIcons?: boolean; - /** - * Max suggestions to show in suggestions. Defaults to 12. - */ - maxVisibleSuggestions?: boolean; - /** - * Names of suggestion types to filter. - */ - filteredTypes?: Record; - } - - export interface IGotoLocationOptions { - /** - * Control how goto-command work when having multiple results. - */ - multiple?: 'peek' | 'gotoAndPeek' | 'goto'; - } - - /** - * Configuration map for codeActionsOnSave - */ - export interface ICodeActionsOnSaveOptions { - [kind: string]: boolean; - } - /** * Configuration options for the editor. */ export interface IEditorOptions { + /** + * This editor is used inside a diff editor. + */ + inDiffEditor?: boolean; /** * The aria label for the editor's textarea (when it is focused). */ @@ -2653,7 +2466,7 @@ declare namespace monaco.editor { * Otherwise, line numbers will not be rendered. * Defaults to true. */ - lineNumbers?: 'on' | 'off' | 'relative' | 'interval' | ((lineNumber: number) => string); + lineNumbers?: LineNumbersType; /** * Controls the minimal number of visible leading and trailing lines surrounding the cursor. * Defaults to 0. @@ -2737,12 +2550,17 @@ declare namespace monaco.editor { * Control the cursor animation style, possible values are 'blink', 'smooth', 'phase', 'expand' and 'solid'. * Defaults to 'blink'. */ - cursorBlinking?: string; + cursorBlinking?: 'blink' | 'smooth' | 'phase' | 'expand' | 'solid'; /** * Zoom the font in the editor when using the mouse wheel in combination with holding Ctrl. * Defaults to false. */ mouseWheelZoom?: boolean; + /** + * Control the mouse pointer style, either 'text' or 'default' or 'copy' + * Defaults to 'text' + */ + mouseStyle?: 'text' | 'default' | 'copy'; /** * Enable smooth caret animation. * Defaults to false. @@ -2752,7 +2570,7 @@ declare namespace monaco.editor { * Control the cursor style, either 'block' or 'line'. * Defaults to 'line'. */ - cursorStyle?: string; + cursorStyle?: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin'; /** * Control the width of the cursor when cursorStyle is set to 'line' */ @@ -2826,7 +2644,7 @@ declare namespace monaco.editor { * Control indentation of wrapped lines. Can be: 'none', 'same', 'indent' or 'deepIndent'. * Defaults to 'same' in vscode and to 'none' in monaco-editor. */ - wrappingIndent?: string; + wrappingIndent?: 'none' | 'same' | 'indent' | 'deepIndent'; /** * Configure word wrapping characters. A break will be introduced before these characters. * Defaults to '{([+'. @@ -2886,6 +2704,11 @@ declare namespace monaco.editor { * Defaults to true */ multiCursorMergeOverlapping?: boolean; + /** + * Configure the behaviour when pasting a text with the line count equal to the cursor count. + * Defaults to 'spread'. + */ + multiCursorPaste?: 'spread' | 'full'; /** * Configure the editor's accessibility support. * Defaults to 'auto'. It is best to leave this to 'auto'. @@ -2903,14 +2726,10 @@ declare namespace monaco.editor { * Enable quick suggestions (shadow suggestions) * Defaults to true. */ - quickSuggestions?: boolean | { - other: boolean; - comments: boolean; - strings: boolean; - }; + quickSuggestions?: boolean | IQuickSuggestionsOptions; /** * Quick suggestions show delay (in ms) - * Defaults to 500 (ms) + * Defaults to 10 (ms) */ quickSuggestionsDelay?: number; /** @@ -2965,7 +2784,7 @@ declare namespace monaco.editor { * Accept suggestions on ENTER. * Defaults to 'on'. */ - acceptSuggestionOnEnter?: boolean | 'on' | 'smart' | 'off'; + acceptSuggestionOnEnter?: 'on' | 'smart' | 'off'; /** * Accept suggestions on provider defined characters. * Defaults to true. @@ -2983,10 +2802,6 @@ declare namespace monaco.editor { * Syntax highlighting is copied. */ copyWithSyntaxHighlighting?: boolean; - /** - * Enable word based suggestions. Defaults to 'true' - */ - wordBasedSuggestions?: boolean; /** * The history mode for suggestions. */ @@ -3004,7 +2819,7 @@ declare namespace monaco.editor { /** * Enable tab completion. */ - tabCompletion?: boolean | 'on' | 'off' | 'onlySnippets'; + tabCompletion?: 'on' | 'off' | 'onlySnippets'; /** * Enable selection highlight. * Defaults to true. @@ -3024,10 +2839,6 @@ declare namespace monaco.editor { * Control the behavior and rendering of the code action lightbulb. */ lightbulb?: IEditorLightbulbOptions; - /** - * Code action kinds to be run on save. - */ - codeActionsOnSave?: ICodeActionsOnSaveOptions; /** * Timeout for running code actions on save. */ @@ -3088,7 +2899,7 @@ declare namespace monaco.editor { /** * The font weight */ - fontWeight?: 'normal' | 'bold' | 'bolder' | 'lighter' | 'initial' | 'inherit' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; + fontWeight?: string; /** * The font size */ @@ -3142,34 +2953,10 @@ declare namespace monaco.editor { reverse?: boolean; } - export enum RenderMinimap { - None = 0, - Small = 1, - Large = 2, - SmallBlocks = 3, - LargeBlocks = 4 - } - /** - * Describes how to indent wrapped lines. + * An event describing that the configuration of the editor has changed. */ - export enum WrappingIndent { - /** - * No indentation => wrapped lines begin at column 1. - */ - None = 0, - /** - * Same => wrapped lines get the same indentation as the parent. - */ - Same = 1, - /** - * Indent => wrapped lines get +1 indentation toward the parent. - */ - Indent = 2, - /** - * DeepIndent => wrapped lines get +2 indentation toward the parent. - */ - DeepIndent = 3 + export class ConfigurationChangedEvent { } /** @@ -3232,187 +3019,58 @@ declare namespace monaco.editor { UnderlineThin = 6 } - export interface InternalEditorScrollbarOptions { - readonly arrowSize: number; - readonly vertical: ScrollbarVisibility; - readonly horizontal: ScrollbarVisibility; - readonly useShadows: boolean; - readonly verticalHasArrows: boolean; - readonly horizontalHasArrows: boolean; - readonly handleMouseWheel: boolean; - readonly horizontalScrollbarSize: number; - readonly horizontalSliderSize: number; - readonly verticalScrollbarSize: number; - readonly verticalSliderSize: number; - readonly mouseWheelScrollSensitivity: number; - readonly fastScrollSensitivity: number; + /** + * Configuration options for editor find widget + */ + export interface IEditorFindOptions { + /** + * Controls if we seed search string in the Find Widget with editor selection. + */ + seedSearchStringFromSelection?: boolean; + /** + * Controls if Find in Selection flag is turned on when multiple lines of text are selected in the editor. + */ + autoFindInSelection?: boolean; + addExtraSpaceOnTop?: boolean; } - export interface InternalEditorMinimapOptions { - readonly enabled: boolean; - readonly side: 'right' | 'left'; - readonly showSlider: 'always' | 'mouseover'; - readonly renderCharacters: boolean; - readonly maxColumn: number; - } - - export interface InternalEditorFindOptions { - readonly seedSearchStringFromSelection: boolean; - readonly autoFindInSelection: boolean; - readonly addExtraSpaceOnTop: boolean; - } - - export interface InternalEditorHoverOptions { - readonly enabled: boolean; - readonly delay: number; - readonly sticky: boolean; - } - - export interface InternalGoToLocationOptions { - readonly multiple: 'peek' | 'gotoAndPeek' | 'goto'; - } - - export interface InternalSuggestOptions { - readonly filterGraceful: boolean; - readonly snippets: 'top' | 'bottom' | 'inline' | 'none'; - readonly snippetsPreventQuickSuggestions: boolean; - readonly localityBonus: boolean; - readonly shareSuggestSelections: boolean; - readonly showIcons: boolean; - readonly maxVisibleSuggestions: number; - readonly filteredTypes: Record; - } - - export interface InternalParameterHintOptions { - readonly enabled: boolean; - readonly cycle: boolean; - } - - export interface EditorWrappingInfo { - readonly inDiffEditor: boolean; - readonly isDominatedByLongLines: boolean; - readonly isWordWrapMinified: boolean; - readonly isViewportWrapping: boolean; - readonly wrappingColumn: number; - readonly wrappingIndent: WrappingIndent; - readonly wordWrapBreakBeforeCharacters: string; - readonly wordWrapBreakAfterCharacters: string; - readonly wordWrapBreakObtrusiveCharacters: string; - } - - export enum RenderLineNumbersType { - Off = 0, - On = 1, - Relative = 2, - Interval = 3, - Custom = 4 - } - - export interface InternalEditorViewOptions { - readonly extraEditorClassName: string; - readonly disableMonospaceOptimizations: boolean; - readonly rulers: number[]; - readonly ariaLabel: string; - readonly renderLineNumbers: RenderLineNumbersType; - readonly renderCustomLineNumbers: ((lineNumber: number) => string) | null; - readonly cursorSurroundingLines: number; - readonly renderFinalNewline: boolean; - readonly selectOnLineNumbers: boolean; - readonly glyphMargin: boolean; - readonly revealHorizontalRightPadding: number; - readonly roundedSelection: boolean; - readonly overviewRulerLanes: number; - readonly overviewRulerBorder: boolean; - readonly cursorBlinking: TextEditorCursorBlinkingStyle; - readonly mouseWheelZoom: boolean; - readonly cursorSmoothCaretAnimation: boolean; - readonly cursorStyle: TextEditorCursorStyle; - readonly cursorWidth: number; - readonly hideCursorInOverviewRuler: boolean; - readonly scrollBeyondLastLine: boolean; - readonly scrollBeyondLastColumn: number; - readonly smoothScrolling: boolean; - readonly stopRenderingLineAfter: number; - readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all'; - readonly renderControlCharacters: boolean; - readonly fontLigatures: boolean; - readonly renderIndentGuides: boolean; - readonly highlightActiveIndentGuide: boolean; - readonly renderLineHighlight: 'none' | 'gutter' | 'line' | 'all'; - readonly scrollbar: InternalEditorScrollbarOptions; - readonly minimap: InternalEditorMinimapOptions; - readonly fixedOverflowWidgets: boolean; - } - - export interface EditorContribOptions { - readonly selectionClipboard: boolean; - readonly hover: InternalEditorHoverOptions; - readonly links: boolean; - readonly contextmenu: boolean; - readonly quickSuggestions: boolean | { - other: boolean; - comments: boolean; - strings: boolean; - }; - readonly quickSuggestionsDelay: number; - readonly parameterHints: InternalParameterHintOptions; - readonly formatOnType: boolean; - readonly formatOnPaste: boolean; - readonly suggestOnTriggerCharacters: boolean; - readonly acceptSuggestionOnEnter: 'on' | 'smart' | 'off'; - readonly acceptSuggestionOnCommitCharacter: boolean; - readonly wordBasedSuggestions: boolean; - readonly suggestSelection: 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix'; - readonly suggestFontSize: number; - readonly suggestLineHeight: number; - readonly tabCompletion: 'on' | 'off' | 'onlySnippets'; - readonly suggest: InternalSuggestOptions; - readonly gotoLocation: InternalGoToLocationOptions; - readonly selectionHighlight: boolean; - readonly occurrencesHighlight: boolean; - readonly codeLens: boolean; - readonly folding: boolean; - readonly foldingStrategy: 'auto' | 'indentation'; - readonly showFoldingControls: 'always' | 'mouseover'; - readonly matchBrackets: boolean; - readonly find: InternalEditorFindOptions; - readonly colorDecorators: boolean; - readonly lightbulbEnabled: boolean; - readonly codeActionsOnSave: ICodeActionsOnSaveOptions; - readonly codeActionsOnSaveTimeout: number; - } + export type EditorFindOptions = Readonly>; /** - * Internal configuration options (transformed or computed) for the editor. + * Configuration options for go to location */ - export class InternalEditorOptions { - readonly _internalEditorOptionsBrand: void; - readonly canUseLayerHinting: boolean; - readonly pixelRatio: number; - readonly editorClassName: string; - readonly lineHeight: number; - readonly readOnly: boolean; - readonly multiCursorModifier: 'altKey' | 'ctrlKey' | 'metaKey'; - readonly multiCursorMergeOverlapping: boolean; - readonly showUnused: boolean; - readonly wordSeparators: string; - readonly autoClosingBrackets: EditorAutoClosingStrategy; - readonly autoClosingQuotes: EditorAutoClosingStrategy; - readonly autoClosingOvertype: EditorAutoClosingOvertypeStrategy; - readonly autoSurround: EditorAutoSurroundStrategy; - readonly autoIndent: boolean; - readonly useTabStops: boolean; - readonly tabFocusMode: boolean; - readonly dragAndDrop: boolean; - readonly emptySelectionClipboard: boolean; - readonly copyWithSyntaxHighlighting: boolean; - readonly layoutInfo: EditorLayoutInfo; - readonly fontInfo: FontInfo; - readonly viewInfo: InternalEditorViewOptions; - readonly wrappingInfo: EditorWrappingInfo; - readonly contribInfo: EditorContribOptions; + export interface IGotoLocationOptions { + /** + * Control how goto-command work when having multiple results. + */ + multiple?: 'peek' | 'gotoAndPeek' | 'goto'; } + export type GoToLocationOptions = Readonly>; + + /** + * Configuration options for editor hover + */ + export interface IEditorHoverOptions { + /** + * Enable the hover. + * Defaults to true. + */ + enabled?: boolean; + /** + * Delay for showing the hover. + * Defaults to 300. + */ + delay?: number; + /** + * Is the hover sticky such that it can be clicked and its contents selected? + * Defaults to true. + */ + sticky?: boolean; + } + + export type EditorHoverOptions = Readonly>; + /** * A description for the overview ruler position. */ @@ -3435,6 +3093,14 @@ declare namespace monaco.editor { readonly right: number; } + export enum RenderMinimap { + None = 0, + Small = 1, + Large = 2, + SmallBlocks = 3, + LargeBlocks = 4 + } + /** * The internal layout details of the editor. */ @@ -3526,33 +3192,233 @@ declare namespace monaco.editor { } /** - * An event describing that the configuration of the editor has changed. + * Configuration options for editor lightbulb */ - export interface IConfigurationChangedEvent { - readonly canUseLayerHinting: boolean; - readonly pixelRatio: boolean; - readonly editorClassName: boolean; - readonly lineHeight: boolean; - readonly readOnly: boolean; - readonly accessibilitySupport: boolean; - readonly multiCursorModifier: boolean; - readonly multiCursorMergeOverlapping: boolean; - readonly wordSeparators: boolean; - readonly autoClosingBrackets: boolean; - readonly autoClosingQuotes: boolean; - readonly autoClosingOvertype: boolean; - readonly autoSurround: boolean; - readonly autoIndent: boolean; - readonly useTabStops: boolean; - readonly tabFocusMode: boolean; - readonly dragAndDrop: boolean; - readonly emptySelectionClipboard: boolean; - readonly copyWithSyntaxHighlighting: boolean; - readonly layoutInfo: boolean; - readonly fontInfo: boolean; - readonly viewInfo: boolean; - readonly wrappingInfo: boolean; - readonly contribInfo: boolean; + export interface IEditorLightbulbOptions { + /** + * Enable the lightbulb code action. + * Defaults to true. + */ + enabled?: boolean; + } + + export type EditorLightbulbOptions = Readonly>; + + /** + * Configuration options for editor minimap + */ + export interface IEditorMinimapOptions { + /** + * Enable the rendering of the minimap. + * Defaults to true. + */ + enabled?: boolean; + /** + * Control the side of the minimap in editor. + * Defaults to 'right'. + */ + side?: 'right' | 'left'; + /** + * Control the rendering of the minimap slider. + * Defaults to 'mouseover'. + */ + showSlider?: 'always' | 'mouseover'; + /** + * Render the actual text on a line (as opposed to color blocks). + * Defaults to true. + */ + renderCharacters?: boolean; + /** + * Limit the width of the minimap to render at most a certain number of columns. + * Defaults to 120. + */ + maxColumn?: number; + } + + export type EditorMinimapOptions = Readonly>; + + /** + * Configuration options for parameter hints + */ + export interface IEditorParameterHintOptions { + /** + * Enable parameter hints. + * Defaults to true. + */ + enabled?: boolean; + /** + * Enable cycling of parameter hints. + * Defaults to false. + */ + cycle?: boolean; + } + + export type InternalParameterHintOptions = Readonly>; + + /** + * Configuration options for quick suggestions + */ + export interface IQuickSuggestionsOptions { + other: boolean; + comments: boolean; + strings: boolean; + } + + export type ValidQuickSuggestionsOptions = boolean | Readonly>; + + export type LineNumbersType = 'on' | 'off' | 'relative' | 'interval' | ((lineNumber: number) => string); + + export enum RenderLineNumbersType { + Off = 0, + On = 1, + Relative = 2, + Interval = 3, + Custom = 4 + } + + export interface InternalEditorRenderLineNumbersOptions { + readonly renderType: RenderLineNumbersType; + readonly renderFn: ((lineNumber: number) => string) | null; + } + + /** + * Configuration options for editor scrollbars + */ + export interface IEditorScrollbarOptions { + /** + * The size of arrows (if displayed). + * Defaults to 11. + */ + arrowSize?: number; + /** + * Render vertical scrollbar. + * Defaults to 'auto'. + */ + vertical?: 'auto' | 'visible' | 'hidden'; + /** + * Render horizontal scrollbar. + * Defaults to 'auto'. + */ + horizontal?: 'auto' | 'visible' | 'hidden'; + /** + * Cast horizontal and vertical shadows when the content is scrolled. + * Defaults to true. + */ + useShadows?: boolean; + /** + * Render arrows at the top and bottom of the vertical scrollbar. + * Defaults to false. + */ + verticalHasArrows?: boolean; + /** + * Render arrows at the left and right of the horizontal scrollbar. + * Defaults to false. + */ + horizontalHasArrows?: boolean; + /** + * Listen to mouse wheel events and react to them by scrolling. + * Defaults to true. + */ + handleMouseWheel?: boolean; + /** + * Height in pixels for the horizontal scrollbar. + * Defaults to 10 (px). + */ + horizontalScrollbarSize?: number; + /** + * Width in pixels for the vertical scrollbar. + * Defaults to 10 (px). + */ + verticalScrollbarSize?: number; + /** + * Width in pixels for the vertical slider. + * Defaults to `verticalScrollbarSize`. + */ + verticalSliderSize?: number; + /** + * Height in pixels for the horizontal slider. + * Defaults to `horizontalScrollbarSize`. + */ + horizontalSliderSize?: number; + } + + export interface InternalEditorScrollbarOptions { + readonly arrowSize: number; + readonly vertical: ScrollbarVisibility; + readonly horizontal: ScrollbarVisibility; + readonly useShadows: boolean; + readonly verticalHasArrows: boolean; + readonly horizontalHasArrows: boolean; + readonly handleMouseWheel: boolean; + readonly horizontalScrollbarSize: number; + readonly horizontalSliderSize: number; + readonly verticalScrollbarSize: number; + readonly verticalSliderSize: number; + } + + /** + * Configuration options for editor suggest widget + */ + export interface ISuggestOptions { + /** + * Enable graceful matching. Defaults to true. + */ + filterGraceful?: boolean; + /** + * Prevent quick suggestions when a snippet is active. Defaults to true. + */ + snippetsPreventQuickSuggestions?: boolean; + /** + * Favours words that appear close to the cursor. + */ + localityBonus?: boolean; + /** + * Enable using global storage for remembering suggestions. + */ + shareSuggestSelections?: boolean; + /** + * Enable or disable icons in suggestions. Defaults to true. + */ + showIcons?: boolean; + /** + * Max suggestions to show in suggestions. Defaults to 12. + */ + maxVisibleSuggestions?: number; + /** + * Names of suggestion types to filter. + */ + filteredTypes?: Record; + } + + export type InternalSuggestOptions = Readonly>; + + /** + * Describes how to indent wrapped lines. + */ + export enum WrappingIndent { + /** + * No indentation => wrapped lines begin at column 1. + */ + None = 0, + /** + * Same => wrapped lines get the same indentation as the parent. + */ + Same = 1, + /** + * Indent => wrapped lines get +1 indentation toward the parent. + */ + Indent = 2, + /** + * DeepIndent => wrapped lines get +2 indentation toward the parent. + */ + DeepIndent = 3 + } + + export interface EditorWrappingInfo { + readonly isDominatedByLongLines: boolean; + readonly isWordWrapMinified: boolean; + readonly isViewportWrapping: boolean; + readonly wrappingColumn: number; } /** @@ -3875,7 +3741,7 @@ declare namespace monaco.editor { * An event emitted when the configuration of the editor has changed. (e.g. `editor.updateOptions()`) * @event */ - onDidChangeConfiguration(listener: (e: IConfigurationChangedEvent) => void): IDisposable; + onDidChangeConfiguration(listener: (e: ConfigurationChangedEvent) => void): IDisposable; /** * An event emitted when the cursor position has changed. * @event @@ -4001,9 +3867,9 @@ declare namespace monaco.editor { */ setModel(model: ITextModel | null): void; /** - * Returns the current editor's configuration + * Returns the editor's configuration (without any validation or defaults). */ - getConfiguration(): InternalEditorOptions; + getRawOptions(): IEditorOptions; /** * Get value of the current model attached to this editor. * @see `ITextModel.getValue` @@ -4246,6 +4112,7 @@ declare namespace monaco.editor { readonly spaceWidth: number; readonly maxDigitWidth: number; } + export class BareFontInfo { readonly _bareFontInfoBrand: void; readonly zoomLevel: number; diff --git a/src/vs/platform/accessibility/common/abstractAccessibilityService.ts b/src/vs/platform/accessibility/common/abstractAccessibilityService.ts index 671d0ba86e..999279151e 100644 --- a/src/vs/platform/accessibility/common/abstractAccessibilityService.ts +++ b/src/vs/platform/accessibility/common/abstractAccessibilityService.ts @@ -10,7 +10,7 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; export abstract class AbstractAccessibilityService extends Disposable implements IAccessibilityService { - _serviceBrand: any; + _serviceBrand: undefined; private _accessibilityModeEnabledContext: IContextKey; protected readonly _onDidChangeAccessibilitySupport = new Emitter(); diff --git a/src/vs/platform/accessibility/common/accessibility.ts b/src/vs/platform/accessibility/common/accessibility.ts index 4f53efbe1a..1e2408102c 100644 --- a/src/vs/platform/accessibility/common/accessibility.ts +++ b/src/vs/platform/accessibility/common/accessibility.ts @@ -10,7 +10,7 @@ import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export const IAccessibilityService = createDecorator('accessibilityService'); export interface IAccessibilityService { - _serviceBrand: any; + _serviceBrand: undefined; readonly onDidChangeAccessibilitySupport: Event; diff --git a/src/vs/platform/accessibility/common/accessibilityService.ts b/src/vs/platform/accessibility/common/accessibilityService.ts index 368e3862c5..2df85131aa 100644 --- a/src/vs/platform/accessibility/common/accessibilityService.ts +++ b/src/vs/platform/accessibility/common/accessibilityService.ts @@ -10,7 +10,7 @@ import { AbstractAccessibilityService } from 'vs/platform/accessibility/common/a export class BrowserAccessibilityService extends AbstractAccessibilityService implements IAccessibilityService { - _serviceBrand: any; + _serviceBrand: undefined; private _accessibilitySupport = AccessibilitySupport.Unknown; diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 01366f7848..612e892729 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -121,7 +121,7 @@ export const IMenuService = createDecorator('menuService'); export interface IMenuService { - _serviceBrand: any; + _serviceBrand: undefined; createMenu(id: MenuId, scopedKeybindingService: IContextKeyService): IMenu; } diff --git a/src/vs/platform/actions/common/menuService.ts b/src/vs/platform/actions/common/menuService.ts index e1f5cdb548..9329a30998 100644 --- a/src/vs/platform/actions/common/menuService.ts +++ b/src/vs/platform/actions/common/menuService.ts @@ -11,7 +11,7 @@ import { ContextKeyExpr, IContextKeyService, IContextKeyChangeEvent } from 'vs/p export class MenuService implements IMenuService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @ICommandService private readonly _commandService: ICommandService diff --git a/src/vs/platform/backup/common/backup.ts b/src/vs/platform/backup/common/backup.ts index ee4856727f..145f9af1f9 100644 --- a/src/vs/platform/backup/common/backup.ts +++ b/src/vs/platform/backup/common/backup.ts @@ -33,7 +33,7 @@ export interface IWorkspaceBackupInfo { } export interface IBackupMainService { - _serviceBrand: any; + _serviceBrand: undefined; isHotExitEnabled(): boolean; diff --git a/src/vs/platform/backup/electron-main/backupMainService.ts b/src/vs/platform/backup/electron-main/backupMainService.ts index 5d6e3a35e7..d5b98fd279 100644 --- a/src/vs/platform/backup/electron-main/backupMainService.ts +++ b/src/vs/platform/backup/electron-main/backupMainService.ts @@ -22,7 +22,7 @@ import { Schemas } from 'vs/base/common/network'; export class BackupMainService implements IBackupMainService { - _serviceBrand: any; + _serviceBrand: undefined; protected backupHome: string; protected workspacesJsonPath: string; @@ -138,7 +138,7 @@ export class BackupMainService implements IBackupMainService { } registerWorkspaceBackupSync(workspaceInfo: IWorkspaceBackupInfo, migrateFrom?: string): string { - if (!this.rootWorkspaces.some(w => workspaceInfo.workspace.id === w.workspace.id)) { + if (!this.rootWorkspaces.some(window => workspaceInfo.workspace.id === window.workspace.id)) { this.rootWorkspaces.push(workspaceInfo); this.saveSync(); } @@ -219,7 +219,7 @@ export class BackupMainService implements IBackupMainService { backupFolder = this.getRandomEmptyWindowId(); } - if (!this.emptyWorkspaces.some(w => !!w.backupFolder && isEqual(w.backupFolder, backupFolder!, !platform.isLinux))) { + if (!this.emptyWorkspaces.some(window => !!window.backupFolder && isEqual(window.backupFolder, backupFolder!, !platform.isLinux))) { this.emptyWorkspaces.push({ backupFolder, remoteAuthority }); this.saveSync(); } @@ -353,7 +353,7 @@ export class BackupMainService implements IBackupMainService { // New empty window backup let newBackupFolder = this.getRandomEmptyWindowId(); - while (this.emptyWorkspaces.some(w => !!w.backupFolder && isEqual(w.backupFolder, newBackupFolder, platform.isLinux))) { + while (this.emptyWorkspaces.some(window => !!window.backupFolder && isEqual(window.backupFolder, newBackupFolder, platform.isLinux))) { newBackupFolder = this.getRandomEmptyWindowId(); } @@ -374,7 +374,7 @@ export class BackupMainService implements IBackupMainService { // New empty window backup let newBackupFolder = this.getRandomEmptyWindowId(); - while (this.emptyWorkspaces.some(w => !!w.backupFolder && isEqual(w.backupFolder, newBackupFolder, platform.isLinux))) { + while (this.emptyWorkspaces.some(window => !!window.backupFolder && isEqual(window.backupFolder, newBackupFolder, platform.isLinux))) { newBackupFolder = this.getRandomEmptyWindowId(); } @@ -457,4 +457,4 @@ export class BackupMainService implements IBackupMainService { protected getLegacyFolderHash(folderPath: string): string { return crypto.createHash('md5').update(platform.isLinux ? folderPath : folderPath.toLowerCase()).digest('hex'); } -} \ No newline at end of file +} diff --git a/src/vs/platform/backup/test/electron-main/backupMainService.test.ts b/src/vs/platform/backup/test/electron-main/backupMainService.test.ts index 705ca74517..dd9ccd4d96 100644 --- a/src/vs/platform/backup/test/electron-main/backupMainService.test.ts +++ b/src/vs/platform/backup/test/electron-main/backupMainService.test.ts @@ -11,7 +11,7 @@ import * as path from 'vs/base/common/path'; import * as pfs from 'vs/base/node/pfs'; import { URI as Uri, URI } from 'vs/base/common/uri'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService'; import { IBackupWorkspacesFormat, ISerializedWorkspace, IWorkspaceBackupInfo } from 'vs/platform/backup/common/backup'; import { HotExitConfiguration } from 'vs/platform/files/common/files'; @@ -32,7 +32,7 @@ suite('BackupMainService', () => { const backupHome = path.join(parentDir, 'Backups'); const backupWorkspacesPath = path.join(backupHome, 'workspaces.json'); - const environmentService = new EnvironmentService(parseArgs(process.argv), process.execPath); + const environmentService = new EnvironmentService(parseArgs(process.argv, OPTIONS), process.execPath); class TestBackupMainService extends BackupMainService { @@ -322,7 +322,7 @@ suite('BackupMainService', () => { assert.deepEqual(json.folderURIWorkspaces, [URI.file(folderPath).toString()]); assert.deepEqual(json.rootURIWorkspaces, [{ id: workspace.id, configURIPath: URI.file(workspacePath).toString() }]); - assertEqualUris(service.getWorkspaceBackups().map(w => w.workspace.configPath), [workspace.configPath]); + assertEqualUris(service.getWorkspaceBackups().map(window => window.workspace.configPath), [workspace.configPath]); }); }); @@ -731,4 +731,4 @@ suite('BackupMainService', () => { } }); }); -}); \ No newline at end of file +}); diff --git a/src/vs/platform/clipboard/browser/clipboardService.ts b/src/vs/platform/clipboard/browser/clipboardService.ts index b077d4531b..b30f50f6ba 100644 --- a/src/vs/platform/clipboard/browser/clipboardService.ts +++ b/src/vs/platform/clipboard/browser/clipboardService.ts @@ -6,11 +6,10 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { URI } from 'vs/base/common/uri'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class BrowserClipboardService implements IClipboardService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private _internalResourcesClipboard: URI[] | undefined; diff --git a/src/vs/platform/clipboard/common/clipboardService.ts b/src/vs/platform/clipboard/common/clipboardService.ts index e5dbdc4b0e..d0882e3b2c 100644 --- a/src/vs/platform/clipboard/common/clipboardService.ts +++ b/src/vs/platform/clipboard/common/clipboardService.ts @@ -10,7 +10,7 @@ export const IClipboardService = createDecorator('clipboardSe export interface IClipboardService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Writes text to the system clipboard. diff --git a/src/vs/platform/clipboard/electron-browser/clipboardService.ts b/src/vs/platform/clipboard/electron-browser/clipboardService.ts index 88ecdda1fc..db17482b56 100644 --- a/src/vs/platform/clipboard/electron-browser/clipboardService.ts +++ b/src/vs/platform/clipboard/electron-browser/clipboardService.ts @@ -12,7 +12,7 @@ export class ClipboardService implements IClipboardService { private static FILE_FORMAT = 'code/file-list'; // Clipboard format for files - _serviceBrand: any; + _serviceBrand: undefined; async writeText(text: string, type?: 'selection' | 'clipboard'): Promise { clipboard.writeText(text, type); diff --git a/src/vs/platform/commands/common/commands.ts b/src/vs/platform/commands/common/commands.ts index 6a950b0e75..47c5305687 100644 --- a/src/vs/platform/commands/common/commands.ts +++ b/src/vs/platform/commands/common/commands.ts @@ -19,7 +19,7 @@ export interface ICommandEvent { } export interface ICommandService { - _serviceBrand: any; + _serviceBrand: undefined; onWillExecuteCommand: Event; onDidExecuteCommand: Event; executeCommand(commandId: string, ...args: any[]): Promise; diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 901f0041b5..4d2dd2fad0 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -63,7 +63,7 @@ export interface IConfigurationChangeEvent { } export interface IConfigurationService { - _serviceBrand: any; + _serviceBrand: undefined; onDidChangeConfiguration: Event; diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index cd25f1f52c..e60c4e8da1 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -442,7 +442,7 @@ export class Configuration { return this._defaultConfiguration; } - private _userConfiguration: ConfigurationModel | null; + private _userConfiguration: ConfigurationModel | null = null; get userConfiguration(): ConfigurationModel { if (!this._userConfiguration) { this._userConfiguration = this._remoteUserConfiguration.isEmpty() ? this._localUserConfiguration : this._localUserConfiguration.merge(this._remoteUserConfiguration); diff --git a/src/vs/platform/configuration/common/configurationRegistry.ts b/src/vs/platform/configuration/common/configurationRegistry.ts index deff85d629..056f4a7956 100644 --- a/src/vs/platform/configuration/common/configurationRegistry.ts +++ b/src/vs/platform/configuration/common/configurationRegistry.ts @@ -140,6 +140,7 @@ type SettingProperties = { [key: string]: any }; export const allSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} }; export const applicationSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} }; export const machineSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} }; +export const machineOverridableSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} }; export const windowSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} }; export const resourceSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} }; @@ -169,7 +170,7 @@ class ConfigurationRegistry implements IConfigurationRegistry { properties: {} }; this.configurationContributors = [this.defaultOverridesConfigurationNode]; - this.editorConfigurationSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown editor configuration setting' }; + this.editorConfigurationSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown editor configuration setting', allowsTrailingCommas: true, allowComments: true }; this.configurationProperties = {}; this.excludedConfigurationProperties = {}; this.computeOverridePropertyPattern(); @@ -213,6 +214,9 @@ class ConfigurationRegistry implements IConfigurationRegistry { case ConfigurationScope.MACHINE: delete machineSettings.properties[key]; break; + case ConfigurationScope.MACHINE_OVERRIDABLE: + delete machineOverridableSettings.properties[key]; + break; case ConfigurationScope.WINDOW: delete windowSettings.properties[key]; break; @@ -364,6 +368,9 @@ class ConfigurationRegistry implements IConfigurationRegistry { case ConfigurationScope.MACHINE: machineSettings.properties[key] = properties[key]; break; + case ConfigurationScope.MACHINE_OVERRIDABLE: + machineOverridableSettings.properties[key] = properties[key]; + break; case ConfigurationScope.WINDOW: windowSettings.properties[key] = properties[key]; break; @@ -402,6 +409,7 @@ class ConfigurationRegistry implements IConfigurationRegistry { delete allSettings.patternProperties[this.overridePropertyPattern]; delete applicationSettings.patternProperties[this.overridePropertyPattern]; delete machineSettings.patternProperties[this.overridePropertyPattern]; + delete machineOverridableSettings.patternProperties[this.overridePropertyPattern]; delete windowSettings.patternProperties[this.overridePropertyPattern]; delete resourceSettings.patternProperties[this.overridePropertyPattern]; @@ -410,6 +418,7 @@ class ConfigurationRegistry implements IConfigurationRegistry { allSettings.patternProperties[this.overridePropertyPattern] = patternProperties; applicationSettings.patternProperties[this.overridePropertyPattern] = patternProperties; machineSettings.patternProperties[this.overridePropertyPattern] = patternProperties; + machineOverridableSettings.patternProperties[this.overridePropertyPattern] = patternProperties; windowSettings.patternProperties[this.overridePropertyPattern] = patternProperties; resourceSettings.patternProperties[this.overridePropertyPattern] = patternProperties; diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index 1489847108..fbd923f467 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -17,7 +17,7 @@ import { Schemas } from 'vs/base/common/network'; export class ConfigurationService extends Disposable implements IConfigurationService, IDisposable { - _serviceBrand: any; + _serviceBrand: undefined; private configuration: Configuration; private userConfigModelWatcher: ConfigWatcher | undefined; diff --git a/src/vs/platform/configuration/test/common/testConfigurationService.ts b/src/vs/platform/configuration/test/common/testConfigurationService.ts index 3908ce5de1..507fb65aef 100644 --- a/src/vs/platform/configuration/test/common/testConfigurationService.ts +++ b/src/vs/platform/configuration/test/common/testConfigurationService.ts @@ -8,7 +8,7 @@ import { URI } from 'vs/base/common/uri'; import { getConfigurationKeys, IConfigurationOverrides, IConfigurationService, getConfigurationValue, isConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; export class TestConfigurationService implements IConfigurationService { - public _serviceBrand: any; + public _serviceBrand: undefined; private configuration = Object.create(null); diff --git a/src/vs/platform/contextkey/browser/contextKeyService.ts b/src/vs/platform/contextkey/browser/contextKeyService.ts index 76ff4a4ffc..6c676e9c27 100644 --- a/src/vs/platform/contextkey/browser/contextKeyService.ts +++ b/src/vs/platform/contextkey/browser/contextKeyService.ts @@ -225,7 +225,7 @@ class CompositeContextKeyChangeEvent implements IContextKeyChangeEvent { } export abstract class AbstractContextKeyService implements IContextKeyService { - public _serviceBrand: any; + public _serviceBrand: undefined; protected _isDisposed: boolean; protected _onDidChangeContext = new PauseableEmitter({ merge: input => new CompositeContextKeyChangeEvent(input) }); diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index 1b7c76ad56..abe9e168aa 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -980,7 +980,7 @@ export interface IContextKeyChangeEvent { } export interface IContextKeyService { - _serviceBrand: any; + _serviceBrand: undefined; dispose(): void; onDidChangeContext: Event; diff --git a/src/vs/platform/contextview/browser/contextMenuHandler.ts b/src/vs/platform/contextview/browser/contextMenuHandler.ts index 4dd3fddd43..2bfd8ac730 100644 --- a/src/vs/platform/contextview/browser/contextMenuHandler.ts +++ b/src/vs/platform/contextview/browser/contextMenuHandler.ts @@ -24,8 +24,8 @@ export interface IContextMenuHandlerOptions { } export class ContextMenuHandler { - private focusToReturn: HTMLElement; - private block: HTMLElement | null; + private focusToReturn: HTMLElement | null = null; + private block: HTMLElement | null = null; private options: IContextMenuHandlerOptions = { blockMouse: true }; constructor( diff --git a/src/vs/platform/contextview/browser/contextMenuService.ts b/src/vs/platform/contextview/browser/contextMenuService.ts index fb2e51eea2..b89c60d39f 100644 --- a/src/vs/platform/contextview/browser/contextMenuService.ts +++ b/src/vs/platform/contextview/browser/contextMenuService.ts @@ -14,7 +14,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { Disposable } from 'vs/base/common/lifecycle'; export class ContextMenuService extends Disposable implements IContextMenuService { - _serviceBrand: any; + _serviceBrand: undefined; private _onDidContextMenu = this._register(new Emitter()); readonly onDidContextMenu: Event = this._onDidContextMenu.event; diff --git a/src/vs/platform/contextview/browser/contextView.ts b/src/vs/platform/contextview/browser/contextView.ts index 33d82fe42c..c3e3f463f3 100644 --- a/src/vs/platform/contextview/browser/contextView.ts +++ b/src/vs/platform/contextview/browser/contextView.ts @@ -13,7 +13,7 @@ export const IContextViewService = createDecorator('context export interface IContextViewService { - _serviceBrand: any; + _serviceBrand: undefined; showContextView(delegate: IContextViewDelegate): void; hideContextView(data?: any): void; @@ -37,7 +37,7 @@ export const IContextMenuService = createDecorator('context export interface IContextMenuService { - _serviceBrand: any; + _serviceBrand: undefined; showContextMenu(delegate: IContextMenuDelegate): void; onDidContextMenu: Event; // TODO@isidor these event should be removed once we get async context menus diff --git a/src/vs/platform/contextview/browser/contextViewService.ts b/src/vs/platform/contextview/browser/contextViewService.ts index eb6ea4c22b..e62f0ab7fd 100644 --- a/src/vs/platform/contextview/browser/contextViewService.ts +++ b/src/vs/platform/contextview/browser/contextViewService.ts @@ -9,7 +9,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; export class ContextViewService extends Disposable implements IContextViewService { - _serviceBrand: any; + _serviceBrand: undefined; private contextView: ContextView; diff --git a/src/vs/platform/debug/common/extensionHostDebug.ts b/src/vs/platform/debug/common/extensionHostDebug.ts index 8f25bca59d..4593debff5 100644 --- a/src/vs/platform/debug/common/extensionHostDebug.ts +++ b/src/vs/platform/debug/common/extensionHostDebug.ts @@ -34,7 +34,7 @@ export interface ICloseSessionEvent { } export interface IExtensionHostDebugService { - _serviceBrand: any; + _serviceBrand: undefined; reload(sessionId: string): void; onReload: Event; diff --git a/src/vs/platform/debug/common/extensionHostDebugIpc.ts b/src/vs/platform/debug/common/extensionHostDebugIpc.ts index 5183771e4c..35870be158 100644 --- a/src/vs/platform/debug/common/extensionHostDebugIpc.ts +++ b/src/vs/platform/debug/common/extensionHostDebugIpc.ts @@ -54,7 +54,7 @@ export class ExtensionHostDebugBroadcastChannel implements IServerChan export class ExtensionHostDebugChannelClient extends Disposable implements IExtensionHostDebugService { - _serviceBrand: any; + _serviceBrand: undefined; constructor(private channel: IChannel) { super(); diff --git a/src/vs/platform/diagnostics/node/diagnosticsIpc.ts b/src/vs/platform/diagnostics/node/diagnosticsIpc.ts index cdb3e6a7e8..365e25431e 100644 --- a/src/vs/platform/diagnostics/node/diagnosticsIpc.ts +++ b/src/vs/platform/diagnostics/node/diagnosticsIpc.ts @@ -7,7 +7,6 @@ import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IRemoteDiagnosticInfo, IRemoteDiagnosticError, SystemInfo, PerformanceInfo } from 'vs/platform/diagnostics/common/diagnostics'; import { IDiagnosticsService } from './diagnosticsService'; import { Event } from 'vs/base/common/event'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IMainProcessInfo } from 'vs/platform/launch/common/launchService'; import { IWorkspace } from 'vs/platform/workspace/common/workspace'; @@ -37,7 +36,7 @@ export class DiagnosticsChannel implements IServerChannel { export class DiagnosticsService implements IDiagnosticsService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; constructor(private channel: IChannel) { } diff --git a/src/vs/platform/diagnostics/node/diagnosticsService.ts b/src/vs/platform/diagnostics/node/diagnosticsService.ts index 1b5680c4c4..169bc3c60c 100644 --- a/src/vs/platform/diagnostics/node/diagnosticsService.ts +++ b/src/vs/platform/diagnostics/node/diagnosticsService.ts @@ -23,7 +23,7 @@ export const ID = 'diagnosticsService'; export const IDiagnosticsService = createDecorator(ID); export interface IDiagnosticsService { - _serviceBrand: any; + _serviceBrand: undefined; getPerformanceInfo(mainProcessInfo: IMainProcessInfo, remoteInfo: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise; getSystemInfo(mainProcessInfo: IMainProcessInfo, remoteInfo: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise; @@ -248,7 +248,7 @@ export function collectLaunchConfigs(folder: string): Promise { - type WorkspaceStatItemClassification = { - name: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - count: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; - }; type WorkspaceStatsClassification = { 'workspace.id': { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - fileTypes: WorkspaceStatItemClassification; - configTypes: WorkspaceStatItemClassification; - launchConfigs: WorkspaceStatItemClassification; + fileTypes: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + configTypes: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + launchConfigs: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; }; type WorkspaceStatsEvent = { 'workspace.id': string | undefined; diff --git a/src/vs/platform/dialogs/browser/dialogService.ts b/src/vs/platform/dialogs/browser/dialogService.ts index 92928d95e0..975de2e60a 100644 --- a/src/vs/platform/dialogs/browser/dialogService.ts +++ b/src/vs/platform/dialogs/browser/dialogService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { IDialogService, IDialogOptions, IConfirmation, IConfirmationResult, DialogType } from 'vs/platform/dialogs/common/dialogs'; +import { IDialogService, IDialogOptions, IConfirmation, IConfirmationResult, DialogType, IShowResult } from 'vs/platform/dialogs/common/dialogs'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { ILogService } from 'vs/platform/log/common/log'; import Severity from 'vs/base/common/severity'; @@ -17,7 +17,7 @@ import { EventHelper } from 'vs/base/browser/dom'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; export class DialogService implements IDialogService { - _serviceBrand: any; + _serviceBrand: undefined; private allowableCommands = ['copy', 'cut']; @@ -78,7 +78,7 @@ export class DialogService implements IDialogService { return (severity === Severity.Info) ? 'question' : (severity === Severity.Error) ? 'error' : (severity === Severity.Warning) ? 'warning' : 'none'; } - async show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise { + async show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise { this.logService.trace('DialogService#show', message); const dialogDisposables = new DisposableStore(); @@ -97,7 +97,9 @@ export class DialogService implements IDialogService { EventHelper.stop(event, true); } } - } + }, + checkboxLabel: options && options.checkbox ? options.checkbox.label : undefined, + checkboxChecked: options && options.checkbox ? options.checkbox.checked : undefined }); dialogDisposables.add(dialog); @@ -106,6 +108,9 @@ export class DialogService implements IDialogService { const result = await dialog.show(); dialogDisposables.dispose(); - return result.button; + return { + choice: result.button, + checkboxChecked: result.checkboxChecked + }; } } diff --git a/src/vs/platform/dialogs/common/dialogs.ts b/src/vs/platform/dialogs/common/dialogs.ts index 6351b1ba57..dda74c3614 100644 --- a/src/vs/platform/dialogs/common/dialogs.ts +++ b/src/vs/platform/dialogs/common/dialogs.ts @@ -41,6 +41,22 @@ export interface IConfirmationResult { checkboxChecked?: boolean; } +export interface IShowResult { + + /** + * Selected choice index. If the user refused to choose, + * then a promise with index of `cancelId` option is returned. If there is no such + * option then promise with index `0` is returned. + */ + choice: number; + + /** + * This will only be defined if the confirmation was created + * with the checkbox option defined. + */ + checkboxChecked?: boolean; +} + export interface IPickAndOpenOptions { forceNewWindow?: boolean; defaultUri?: URI; @@ -127,8 +143,10 @@ export const IDialogService = createDecorator('dialogService'); export interface IDialogOptions { cancelId?: number; detail?: string; - checkboxLabel?: string; - checkboxChecked?: boolean; + checkbox?: { + label: string; + checked?: boolean; + }; } /** @@ -139,7 +157,7 @@ export interface IDialogOptions { */ export interface IDialogService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Ask the user for confirmation with a modal dialog. @@ -153,7 +171,7 @@ export interface IDialogService { * then a promise with index of `cancelId` option is returned. If there is no such * option then promise with index `0` is returned. */ - show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise; + show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise; } export const IFileDialogService = createDecorator('fileDialogService'); @@ -163,7 +181,7 @@ export const IFileDialogService = createDecorator('fileDialo */ export interface IFileDialogService { - _serviceBrand: any; + _serviceBrand: undefined; /** * The default path for a new file based on previously used files. diff --git a/src/vs/platform/dialogs/node/dialogIpc.ts b/src/vs/platform/dialogs/node/dialogIpc.ts index 4772ce01f8..9f71b02b82 100644 --- a/src/vs/platform/dialogs/node/dialogIpc.ts +++ b/src/vs/platform/dialogs/node/dialogIpc.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IDialogService, IConfirmation, IConfirmationResult } from 'vs/platform/dialogs/common/dialogs'; +import { IDialogService, IConfirmation, IConfirmationResult, IShowResult } from 'vs/platform/dialogs/common/dialogs'; import Severity from 'vs/base/common/severity'; import { Event } from 'vs/base/common/event'; @@ -27,15 +27,15 @@ export class DialogChannel implements IServerChannel { export class DialogChannelClient implements IDialogService { - _serviceBrand: any; + _serviceBrand: undefined; constructor(private channel: IChannel) { } - show(severity: Severity, message: string, options: string[]): Promise { + show(severity: Severity, message: string, options: string[]): Promise { return this.channel.call('show', [severity, message, options]); } confirm(confirmation: IConfirmation): Promise { return this.channel.call('confirm', [confirmation]); } -} \ No newline at end of file +} diff --git a/src/vs/platform/download/common/download.ts b/src/vs/platform/download/common/download.ts index 61c457760e..011c733146 100644 --- a/src/vs/platform/download/common/download.ts +++ b/src/vs/platform/download/common/download.ts @@ -11,7 +11,7 @@ export const IDownloadService = createDecorator('downloadServi export interface IDownloadService { - _serviceBrand: any; + _serviceBrand: undefined; download(uri: URI, to: URI, cancellationToken?: CancellationToken): Promise; diff --git a/src/vs/platform/download/common/downloadIpc.ts b/src/vs/platform/download/common/downloadIpc.ts index d8223e2506..37627eb0e1 100644 --- a/src/vs/platform/download/common/downloadIpc.ts +++ b/src/vs/platform/download/common/downloadIpc.ts @@ -27,7 +27,7 @@ export class DownloadServiceChannel implements IServerChannel { export class DownloadServiceChannelClient implements IDownloadService { - _serviceBrand: any; + _serviceBrand: undefined; constructor(private channel: IChannel, private getUriTransformer: () => IURITransformer | null) { } diff --git a/src/vs/platform/download/common/downloadService.ts b/src/vs/platform/download/common/downloadService.ts index 9d6bb2b882..3da98d5e1a 100644 --- a/src/vs/platform/download/common/downloadService.ts +++ b/src/vs/platform/download/common/downloadService.ts @@ -12,7 +12,7 @@ import { Schemas } from 'vs/base/common/network'; export class DownloadService implements IDownloadService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @IRequestService private readonly requestService: IRequestService, diff --git a/src/vs/platform/driver/common/driver.ts b/src/vs/platform/driver/common/driver.ts index 694e5bf37d..b48cc825d8 100644 --- a/src/vs/platform/driver/common/driver.ts +++ b/src/vs/platform/driver/common/driver.ts @@ -19,7 +19,7 @@ export interface IElement { } export interface IDriver { - _serviceBrand: any; + _serviceBrand: undefined; getWindowIds(): Promise; capturePage(windowId: number): Promise; diff --git a/src/vs/platform/driver/electron-main/driver.ts b/src/vs/platform/driver/electron-main/driver.ts index 566830d3a1..4621c0e333 100644 --- a/src/vs/platform/driver/electron-main/driver.ts +++ b/src/vs/platform/driver/electron-main/driver.ts @@ -25,7 +25,7 @@ function isSilentKeyCode(keyCode: KeyCode) { export class Driver implements IDriver, IWindowDriverRegistry { - _serviceBrand: any; + _serviceBrand: undefined; private registeredWindowIds = new Set(); private reloadingWindowIds = new Set(); diff --git a/src/vs/platform/driver/node/driver.ts b/src/vs/platform/driver/node/driver.ts index 2cf10644b4..92a96fd755 100644 --- a/src/vs/platform/driver/node/driver.ts +++ b/src/vs/platform/driver/node/driver.ts @@ -42,7 +42,7 @@ export class DriverChannel implements IServerChannel { export class DriverChannelClient implements IDriver { - _serviceBrand: any; + _serviceBrand: undefined; constructor(private channel: IChannel) { } @@ -136,7 +136,7 @@ export class WindowDriverRegistryChannel implements IServerChannel { export class WindowDriverRegistryChannelClient implements IWindowDriverRegistry { - _serviceBrand: any; + _serviceBrand: undefined; constructor(private channel: IChannel) { } @@ -177,7 +177,7 @@ export class WindowDriverChannel implements IServerChannel { export class WindowDriverChannelClient implements IWindowDriver { - _serviceBrand: any; + _serviceBrand: undefined; constructor(private channel: IChannel) { } diff --git a/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts index 71712396d3..da2c36ad32 100644 --- a/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -82,15 +82,26 @@ export interface IResourceInput extends IBaseResourceInput { export enum EditorActivation { /** - * Activate the editor after it opened. + * Activate the editor after it opened. This will automatically restore + * the editor if it is minimized. */ ACTIVATE, + /** + * Only restore the editor if it is minimized but do not activate it. + * + * Note: will only work in combination with the `preserveFocus: true` option. + * Otherwise, if focus moves into the editor, it will activate and restore + * automatically. + */ + RESTORE, + /** * Preserve the current active editor. * - * Note: will only work in combination with the - * `preserveFocus: true` option. + * Note: will only work in combination with the `preserveFocus: true` option. + * Otherwise, if focus moves into the editor, it will activate and restore + * automatically. */ PRESERVE } @@ -107,7 +118,8 @@ export interface IEditorOptions { /** * This option is only relevant if an editor is opened into a group that is not active - * already and allows to control if the inactive group should become active or not. + * already and allows to control if the inactive group should become active, restored + * or preserved. * * By default, the editor group will become active unless `preserveFocus` or `inactive` * is specified. @@ -162,6 +174,11 @@ export interface IEditorOptions { * message as needed. By default, an error will be presented as notification if opening was not possible. */ readonly ignoreError?: boolean; + + /** + * Does not use editor overrides while opening the editor + */ + readonly ignoreOverrides?: boolean; } export interface ITextEditorSelection { diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 177ebea906..167eaab5e7 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -3,13 +3,13 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; export interface ParsedArgs { _: string[]; - 'folder-uri'?: string | string[]; - 'file-uri'?: string | string[]; + 'folder-uri'?: string[]; // undefined or array of 1 or more + 'file-uri'?: string[]; // undefined or array of 1 or more _urls?: string[]; help?: boolean; version?: boolean; @@ -25,7 +25,7 @@ export interface ParsedArgs { 'reuse-window'?: boolean; locale?: string; 'user-data-dir'?: string; - 'prof-startup'?: string; + 'prof-startup'?: boolean; 'prof-startup-prefix'?: string; 'prof-append-timers'?: string; verbose?: boolean; @@ -36,7 +36,7 @@ export interface ParsedArgs { logExtensionHostCommunication?: boolean; 'extensions-dir'?: string; 'builtin-extensions-dir'?: string; - extensionDevelopmentPath?: string | string[]; // one or more local paths or URIs + extensionDevelopmentPath?: string[]; // // undefined or array of 1 or more local paths or URIs extensionTestsPath?: string; // either a local path or a URI 'extension-development-confirm-save'?: boolean; 'inspect-extensions'?: string; @@ -45,14 +45,14 @@ export interface ParsedArgs { 'inspect-search'?: string; 'inspect-brk-search'?: string; 'disable-extensions'?: boolean; - 'disable-extension'?: string | string[]; + 'disable-extension'?: string[]; // undefined or array of 1 or more 'list-extensions'?: boolean; 'show-versions'?: boolean; 'category'?: string; - 'install-extension'?: string | string[]; - 'uninstall-extension'?: string | string[]; - 'locate-extension'?: string | string[]; - 'enable-proposed-api'?: string | string[]; + 'install-extension'?: string[]; // undefined or array of 1 or more + 'uninstall-extension'?: string[]; // undefined or array of 1 or more + 'locate-extension'?: string[]; // undefined or array of 1 or more + 'enable-proposed-api'?: string[]; // undefined or array of 1 or more 'open-url'?: boolean; 'skip-getting-started'?: boolean; 'skip-release-notes'?: boolean; @@ -61,8 +61,8 @@ export interface ParsedArgs { 'disable-telemetry'?: boolean; 'export-default-configuration'?: string; 'install-source'?: string; - 'disable-updates'?: string; - 'disable-crash-reporter'?: string; + 'disable-updates'?: boolean; + 'disable-crash-reporter'?: boolean; 'skip-add-to-recently-opened'?: boolean; 'max-memory'?: string; 'file-write'?: boolean; @@ -71,7 +71,10 @@ export interface ParsedArgs { 'driver-verbose'?: boolean; remote?: string; 'disable-user-env-probe'?: boolean; - 'enable-remote-auto-shutdown'?: boolean; + 'disable-inspect'?: boolean; + 'force'?: boolean; + 'force-user-env'?: boolean; + // {{SQL CARBON EDIT}} aad?: boolean; database?: string; @@ -80,16 +83,11 @@ export interface ParsedArgs { user?: string; command?: string; // {{SQL CARBON EDIT}} - 'disable-inspect'?: boolean; - 'force'?: boolean; - 'gitCredential'?: string; + // node flags - 'js-flags'?: boolean; + 'js-flags'?: string; 'disable-gpu'?: boolean; 'nolazy'?: boolean; - - // Web flags - 'web-user-data-dir'?: string; } export const IEnvironmentService = createDecorator('environmentService'); @@ -107,7 +105,7 @@ export const BACKUPS = 'Backups'; export interface IEnvironmentService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; args: ParsedArgs; diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 791c2ebe53..d642c873ff 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -20,112 +20,145 @@ const helpCategories = { t: localize('troubleshooting', "Troubleshooting") }; -export interface Option { - id: keyof ParsedArgs; - type: 'boolean' | 'string'; +export interface Option { + type: OptionType; alias?: string; deprecates?: string; // old deprecated id args?: string | string[]; description?: string; cat?: keyof typeof helpCategories; } -//_urls -export const options: Option[] = [ - { id: 'diff', type: 'boolean', cat: 'o', alias: 'd', args: ['file', 'file'], description: localize('diff', "Compare two files with each other.") }, - { id: 'add', type: 'boolean', cat: 'o', alias: 'a', args: 'folder', description: localize('add', "Add folder(s) to the last active window.") }, - { id: 'goto', type: 'boolean', cat: 'o', alias: 'g', args: 'file:line[:character]', description: localize('goto', "Open a file at the path on the specified line and character position.") }, - { id: 'new-window', type: 'boolean', cat: 'o', alias: 'n', description: localize('newWindow', "Force to open a new window.") }, - { id: 'reuse-window', type: 'boolean', cat: 'o', alias: 'r', description: localize('reuseWindow', "Force to open a file or folder in an already opened window.") }, - { id: 'wait', type: 'boolean', cat: 'o', alias: 'w', description: localize('wait', "Wait for the files to be closed before returning.") }, - { id: 'locale', type: 'string', cat: 'o', args: 'locale', description: localize('locale', "The locale to use (e.g. en-US or zh-TW).") }, - { id: 'user-data-dir', type: 'string', cat: 'o', args: 'dir', description: localize('userDataDir', "Specifies the directory that user data is kept in. Can be used to open multiple distinct instances of Code.") }, - { id: 'version', type: 'boolean', cat: 'o', alias: 'v', description: localize('version', "Print version.") }, - { id: 'help', type: 'boolean', cat: 'o', alias: 'h', description: localize('help', "Print usage.") }, - { id: 'telemetry', type: 'boolean', cat: 'o', description: localize('telemetry', "Shows all telemetry events which VS code collects.") }, - { id: 'folder-uri', type: 'string', cat: 'o', args: 'uri', description: localize('folderUri', "Opens a window with given folder uri(s)") }, - { id: 'file-uri', type: 'string', cat: 'o', args: 'uri', description: localize('fileUri', "Opens a window with given file uri(s)") }, - { 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.") }, +export type OptionDescriptions = { + [P in keyof T]: Option>; +}; - { id: 'verbose', type: 'boolean', cat: 't', description: localize('verbose', "Print verbose output (implies --wait).") }, - { id: 'log', type: 'string', cat: 't', args: 'level', description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'.") }, - { id: 'status', type: 'boolean', alias: 's', cat: 't', description: localize('status', "Print process usage and diagnostics information.") }, - { id: 'prof-startup', type: 'boolean', cat: 't', description: localize('prof-startup', "Run CPU profiler during startup") }, - { id: 'disable-extensions', type: 'boolean', deprecates: 'disableExtensions', cat: 't', description: localize('disableExtensions', "Disable all installed extensions.") }, - { id: 'disable-extension', type: 'string', cat: 't', args: 'extension-id', description: localize('disableExtension', "Disable an extension.") }, +type OptionTypeName = + T extends boolean ? 'boolean' : + T extends string ? 'string' : + T extends string[] ? 'string[]' : + T extends undefined ? 'undefined' : + 'unknown'; - { id: 'inspect-extensions', type: 'string', deprecates: 'debugPluginHost', args: 'port', cat: 't', description: localize('inspect-extensions', "Allow debugging and profiling of extensions. Check the developer tools for the connection URI.") }, - { id: 'inspect-brk-extensions', type: 'string', deprecates: 'debugBrkPluginHost', args: 'port', cat: 't', description: localize('inspect-brk-extensions', "Allow debugging and profiling of extensions with the extension host being paused after start. Check the developer tools for the connection URI.") }, - { id: 'disable-gpu', type: 'boolean', cat: 't', description: localize('disableGPU', "Disable GPU hardware acceleration.") }, - { id: 'max-memory', type: 'string', cat: 't', description: localize('maxMemory', "Max memory size for a window (in Mbytes).") }, +export const OPTIONS: OptionDescriptions> = { + 'diff': { type: 'boolean', cat: 'o', alias: 'd', args: ['file', 'file'], description: localize('diff', "Compare two files with each other.") }, + 'add': { type: 'boolean', cat: 'o', alias: 'a', args: 'folder', description: localize('add', "Add folder(s) to the last active window.") }, + 'goto': { type: 'boolean', cat: 'o', alias: 'g', args: 'file:line[:character]', description: localize('goto', "Open a file at the path on the specified line and character position.") }, + 'new-window': { type: 'boolean', cat: 'o', alias: 'n', description: localize('newWindow', "Force to open a new window.") }, + 'reuse-window': { type: 'boolean', cat: 'o', alias: 'r', description: localize('reuseWindow', "Force to open a file or folder in an already opened window.") }, + 'wait': { type: 'boolean', cat: 'o', alias: 'w', description: localize('wait', "Wait for the files to be closed before returning.") }, + 'waitMarkerFilePath': { type: 'string' }, + 'locale': { type: 'string', cat: 'o', args: 'locale', description: localize('locale', "The locale to use (e.g. en-US or zh-TW).") }, + 'user-data-dir': { type: 'string', cat: 'o', args: 'dir', description: localize('userDataDir', "Specifies the directory that user data is kept in. Can be used to open multiple distinct instances of Code.") }, + 'version': { type: 'boolean', cat: 'o', alias: 'v', description: localize('version', "Print version.") }, + 'help': { type: 'boolean', cat: 'o', alias: 'h', description: localize('help', "Print usage.") }, + 'telemetry': { type: 'boolean', cat: 'o', description: localize('telemetry', "Shows all telemetry events which VS code collects.") }, + 'folder-uri': { type: 'string[]', cat: 'o', args: 'uri', description: localize('folderUri', "Opens a window with given folder uri(s)") }, + 'file-uri': { type: 'string[]', cat: 'o', args: 'uri', description: localize('fileUri', "Opens a window with given file uri(s)") }, - { id: 'remote', type: 'string' }, - { id: 'locate-extension', type: 'string' }, - { id: 'extensionDevelopmentPath', type: 'string' }, - { id: 'extensionTestsPath', type: 'string' }, - { id: 'extension-development-confirm-save', type: 'boolean' }, - { id: 'debugId', type: 'string' }, - { id: 'inspect-search', type: 'string', deprecates: 'debugSearch' }, - { id: 'inspect-brk-search', type: 'string', deprecates: 'debugBrkSearch' }, - { id: 'export-default-configuration', type: 'string' }, - { id: 'install-source', type: 'string' }, - { id: 'driver', type: 'string' }, - { id: 'logExtensionHostCommunication', type: 'boolean' }, - { id: 'skip-getting-started', type: 'boolean' }, - { id: 'skip-release-notes', type: 'boolean' }, - { id: 'sticky-quickopen', type: 'boolean' }, - { id: 'disable-restore-windows', type: 'boolean' }, - { id: 'disable-telemetry', type: 'boolean' }, - { id: 'disable-updates', type: 'boolean' }, - { id: 'disable-crash-reporter', type: 'boolean' }, - { id: 'skip-add-to-recently-opened', type: 'boolean' }, - { id: 'unity-launch', type: 'boolean' }, - { id: 'open-url', type: 'boolean' }, - { id: 'file-write', type: 'boolean' }, - { id: 'file-chmod', type: 'boolean' }, - { id: 'driver-verbose', type: 'boolean' }, - { id: 'force', type: 'boolean' }, - { id: 'trace-category-filter', type: 'string' }, - { id: 'trace-options', type: 'string' }, - { id: '_', type: 'string' }, + 'extensions-dir': { type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") }, + 'builtin-extensions-dir': { type: 'string' }, + 'list-extensions': { type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") }, + 'show-versions': { type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extension.") }, + 'category': { type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extension.") }, + '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.") }, + 'uninstall-extension': { type: 'string[]', cat: 'e', args: 'extension-id', description: localize('uninstallExtension', "Uninstalls an extension.") }, + '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.") }, + + 'verbose': { type: 'boolean', cat: 't', description: localize('verbose', "Print verbose output (implies --wait).") }, + 'log': { type: 'string', cat: 't', args: 'level', description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'.") }, + 'status': { type: 'boolean', alias: 's', cat: 't', description: localize('status', "Print process usage and diagnostics information.") }, + 'prof-startup': { type: 'boolean', cat: 't', description: localize('prof-startup', "Run CPU profiler during startup") }, + 'prof-append-timers': { type: 'string' }, + 'prof-startup-prefix': { type: 'string' }, + 'disable-extensions': { type: 'boolean', deprecates: 'disableExtensions', cat: 't', description: localize('disableExtensions', "Disable all installed extensions.") }, + 'disable-extension': { type: 'string[]', cat: 't', args: 'extension-id', description: localize('disableExtension', "Disable an extension.") }, + + 'inspect-extensions': { type: 'string', deprecates: 'debugPluginHost', args: 'port', cat: 't', description: localize('inspect-extensions', "Allow debugging and profiling of extensions. Check the developer tools for the connection URI.") }, + 'inspect-brk-extensions': { type: 'string', deprecates: 'debugBrkPluginHost', args: 'port', cat: 't', description: localize('inspect-brk-extensions', "Allow debugging and profiling of extensions with the extension host being paused after start. Check the developer tools for the connection URI.") }, + 'disable-gpu': { type: 'boolean', cat: 't', description: localize('disableGPU', "Disable GPU hardware acceleration.") }, + 'max-memory': { type: 'string', cat: 't', description: localize('maxMemory', "Max memory size for a window (in Mbytes).") }, + + 'remote': { type: 'string' }, + 'locate-extension': { type: 'string[]' }, + 'extensionDevelopmentPath': { type: 'string[]' }, + 'extensionTestsPath': { type: 'string' }, + 'extension-development-confirm-save': { type: 'boolean' }, + 'debugId': { type: 'string' }, + 'inspect-search': { type: 'string', deprecates: 'debugSearch' }, + 'inspect-brk-search': { type: 'string', deprecates: 'debugBrkSearch' }, + 'export-default-configuration': { type: 'string' }, + 'install-source': { type: 'string' }, + 'driver': { type: 'string' }, + 'logExtensionHostCommunication': { type: 'boolean' }, + 'skip-getting-started': { type: 'boolean' }, + 'skip-release-notes': { type: 'boolean' }, + 'sticky-quickopen': { type: 'boolean' }, + 'disable-restore-windows': { type: 'boolean' }, + 'disable-telemetry': { type: 'boolean' }, + 'disable-updates': { type: 'boolean' }, + 'disable-crash-reporter': { type: 'boolean' }, + 'disable-user-env-probe': { type: 'boolean' }, + 'skip-add-to-recently-opened': { type: 'boolean' }, + 'unity-launch': { type: 'boolean' }, + 'open-url': { type: 'boolean' }, + 'file-write': { type: 'boolean' }, + 'file-chmod': { type: 'boolean' }, + 'driver-verbose': { type: 'boolean' }, + 'force': { type: 'boolean' }, + 'trace': { type: 'boolean' }, + 'trace-category-filter': { type: 'string' }, + 'trace-options': { type: 'string' }, + 'disable-inspect': { type: 'boolean' }, + 'force-user-env': { type: 'boolean' }, // {{SQL CARBON EDIT}} - { id: 'command', type: 'string', alias: 'c', cat: 'o', args: 'command-name', description: localize('commandParameter', 'Name of command to run') }, - { id: 'database', type: 'string', alias: 'D', cat: 'o', args: 'database', description: localize('databaseParameter', 'Database name') }, - { id: 'server', type: 'string', alias: 'S', cat: 'o', args: 'server', description: localize('serverParameter', 'Server name') }, - { id: 'user', type: 'string', alias: 'U', cat: 'o', args: 'user-name', description: localize('userParameter', 'User name for server connection') }, - { id: 'aad', type: 'boolean', cat: 'o', description: localize('aadParameter', 'Use Azure Active Directory authentication for server connection') }, - { id: 'integrated', type: 'boolean', alias: 'E', cat: 'o', description: localize('integratedAuthParameter', 'Use Integrated authentication for server connection') }, + 'command': { type: 'string', alias: 'c', cat: 'o', args: 'command-name', description: localize('commandParameter', 'Name of command to run') }, + 'database': { type: 'string', alias: 'D', cat: 'o', args: 'database', description: localize('databaseParameter', 'Database name') }, + 'server': { type: 'string', alias: 'S', cat: 'o', args: 'server', description: localize('serverParameter', 'Server name') }, + 'user': { type: 'string', alias: 'U', cat: 'o', args: 'user-name', description: localize('userParameter', 'User name for server connection') }, + 'aad': { type: 'boolean', cat: 'o', description: localize('aadParameter', 'Use Azure Active Directory authentication for server connection') }, + 'integrated': { type: 'boolean', alias: 'E', cat: 'o', description: localize('integratedAuthParameter', 'Use Integrated authentication for server connection') }, // {{SQL CARBON EDIT}} - End - { id: 'js-flags', type: 'string' }, // chrome js flags - { id: 'nolazy', type: 'boolean' }, // node inspect -]; + 'js-flags': { type: 'string' }, // chrome js flags + 'nolazy': { type: 'boolean' }, // node inspect + '_urls': { type: 'string[]' }, -export function parseArgs(args: string[], isOptionSupported = (_: Option) => true): ParsedArgs { + _: { type: 'string[]' } // main arguments +}; + +export interface ErrorReporter { + onUnknownOption(id: string): void; + onMultipleValues(id: string, usedValue: string): void; +} + +const ignoringReporter: ErrorReporter = { + onUnknownOption: () => { }, + onMultipleValues: () => { } +}; + +export function parseArgs(args: string[], options: OptionDescriptions, errorReporter: ErrorReporter = ignoringReporter): T { const alias: { [key: string]: string } = {}; const string: string[] = []; const boolean: string[] = []; - for (let o of options) { - if (isOptionSupported(o)) { - if (o.alias) { - alias[o.id] = o.alias; - } + for (let optionId in options) { + if (optionId[0] === '_') { + continue; } - if (o.type === 'string') { - string.push(o.id); + const o = options[optionId]; + if (o.alias) { + alias[optionId] = o.alias; + } + + if (o.type === 'string' || o.type === 'string[]') { + string.push(optionId); if (o.deprecates) { string.push(o.deprecates); } } else if (o.type === 'boolean') { - boolean.push(o.id); + boolean.push(optionId); if (o.deprecates) { boolean.push(o.deprecates); } @@ -133,23 +166,51 @@ export function parseArgs(args: string[], isOptionSupported = (_: Option) => tru } // remote aliases to avoid confusion const parsedArgs = minimist(args, { string, boolean, alias }); - for (const o of options) { + + const cleanedArgs: any = {}; + + // https://github.com/microsoft/vscode/issues/58177 + cleanedArgs._ = parsedArgs._.filter(arg => arg.length > 0); + delete parsedArgs._; + + for (let optionId in options) { + const o = options[optionId]; if (o.alias) { delete parsedArgs[o.alias]; } - if (o.deprecates && parsedArgs.hasOwnProperty(o.deprecates) && !parsedArgs[o.id]) { - parsedArgs[o.id] = parsedArgs[o.deprecates]; + + let val = parsedArgs[optionId]; + if (o.deprecates && parsedArgs.hasOwnProperty(o.deprecates)) { + if (!val) { + val = parsedArgs[o.deprecates]; + } delete parsedArgs[o.deprecates]; } + + if (val) { + if (o.type === 'string[]') { + if (val && !Array.isArray(val)) { + val = [val]; + } + } else if (o.type === 'string') { + if (Array.isArray(val)) { + val = val.pop(); // take the last + errorReporter.onMultipleValues(optionId, val); + } + } + cleanedArgs[optionId] = val; + } + delete parsedArgs[optionId]; } - // https://github.com/microsoft/vscode/issues/58177 - parsedArgs._ = parsedArgs._.filter(arg => arg.length > 0); + for (let key in parsedArgs) { + errorReporter.onUnknownOption(key); + } - return parsedArgs; + return cleanedArgs; } -function formatUsage(option: Option) { +function formatUsage(optionId: string, option: Option) { let args = ''; if (option.args) { if (Array.isArray(option.args)) { @@ -159,30 +220,37 @@ function formatUsage(option: Option) { } } if (option.alias) { - return `-${option.alias} --${option.id}${args}`; + return `-${option.alias} --${optionId}${args}`; } - return `--${option.id}${args}`; + return `--${optionId}${args}`; } // exported only for testing -export function formatOptions(docOptions: Option[], columns: number): string[] { - let usageTexts = docOptions.map(formatUsage); - let argLength = Math.max.apply(null, usageTexts.map(k => k.length)) + 2/*left padding*/ + 1/*right padding*/; +export function formatOptions(options: OptionDescriptions, columns: number): string[] { + let maxLength = 0; + let usageTexts: [string, string][] = []; + for (const optionId in options) { + const o = options[optionId]; + const usageText = formatUsage(optionId, o); + maxLength = Math.max(maxLength, usageText.length); + usageTexts.push([usageText, o.description!]); + } + let argLength = maxLength + 2/*left padding*/ + 1/*right padding*/; if (columns - argLength < 25) { // Use a condensed version on narrow terminals - return docOptions.reduce((r, o, i) => r.concat([` ${usageTexts[i]}`, ` ${o.description}`]), []); + return usageTexts.reduce((r, ut) => r.concat([` ${ut[0]}`, ` ${ut[1]}`]), []); } let descriptionColumns = columns - argLength - 1; let result: string[] = []; - docOptions.forEach((o, i) => { - let usage = usageTexts[i]; - let wrappedDescription = wrapText(o.description!, descriptionColumns); + for (const ut of usageTexts) { + let usage = ut[0]; + let wrappedDescription = wrapText(ut[1], descriptionColumns); let keyPadding = indent(argLength - usage.length - 2/*left padding*/); result.push(' ' + usage + keyPadding + wrappedDescription[0]); for (let i = 1; i < wrappedDescription.length; i++) { result.push(indent(argLength) + wrappedDescription[i]); } - }); + } return result; } @@ -201,7 +269,7 @@ function wrapText(text: string, columns: number): string[] { return lines; } -export function buildHelpMessage(productName: string, executableName: string, version: string, isOptionSupported = (_: Option) => true, isPipeSupported = true): string { +export function buildHelpMessage(productName: string, executableName: string, version: string, options: OptionDescriptions, isPipeSupported = true): string { const columns = (process.stdout).isTTY && (process.stdout).columns || 80; let help = [`${productName} ${version}`]; @@ -216,11 +284,23 @@ export function buildHelpMessage(productName: string, executableName: string, ve } help.push(''); } - for (let helpCategoryKey in helpCategories) { + const optionsByCategory: { [P in keyof typeof helpCategories]?: OptionDescriptions } = {}; + for (const optionId in options) { + const o = options[optionId]; + if (o.description && o.cat) { + let optionsByCat = optionsByCategory[o.cat]; + if (!optionsByCat) { + optionsByCategory[o.cat] = optionsByCat = {}; + } + optionsByCat[optionId] = o; + } + } + + for (let helpCategoryKey in optionsByCategory) { const key = helpCategoryKey; - let categoryOptions = options.filter(o => !!o.description && o.cat === key && isOptionSupported(o)); - if (categoryOptions.length) { + let categoryOptions = optionsByCategory[key]; + if (categoryOptions) { help.push(helpCategories[key]); help.push(...formatOptions(categoryOptions, columns)); help.push(''); @@ -233,32 +313,6 @@ export function buildVersionMessage(version: string | undefined, commit: string return `${version || localize('unknownVersion', "Unknown version")}\n${commit || localize('unknownCommit', "Unknown commit")}\n${process.arch}`; } -/** - * Converts an argument into an array - * @param arg a argument value. Can be undefined, an entry or an array - */ -export function asArray(arg: string | string[] | undefined): string[] { - if (arg) { - if (Array.isArray(arg)) { - return arg; - } - return [arg]; - } - return []; -} - -/** - * Returns whether an argument is present. - */ -export function hasArgs(arg: string | string[] | undefined): boolean { - if (arg) { - if (Array.isArray(arg)) { - return !!arg.length; - } - return true; - } - return false; -} export function addArg(argv: string[], ...args: string[]): string[] { const endOfArgsMarkerIndex = argv.indexOf('--'); diff --git a/src/vs/platform/environment/node/argvHelper.ts b/src/vs/platform/environment/node/argvHelper.ts index ca026ebe8e..0c0581e803 100644 --- a/src/vs/platform/environment/node/argvHelper.ts +++ b/src/vs/platform/environment/node/argvHelper.ts @@ -8,9 +8,19 @@ import { firstIndex } from 'vs/base/common/arrays'; import { localize } from 'vs/nls'; import { ParsedArgs } from '../common/environment'; import { MIN_MAX_MEMORY_SIZE_MB } from 'vs/platform/files/common/files'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, ErrorReporter, OPTIONS } from 'vs/platform/environment/node/argv'; -function validate(args: ParsedArgs): ParsedArgs { +function parseAndValidate(cmdLineArgs: string[], reportWarnings: boolean): ParsedArgs { + const errorReporter: ErrorReporter = { + onUnknownOption: (id) => { + console.warn(localize('unknownOption', "Option '{0}' is unknown. Ignoring.", id)); + }, + onMultipleValues: (id, val) => { + console.warn(localize('multipleValues', "Option '{0}' is defined more than once. Using value '{1}.'", id, val)); + } + }; + + const args = parseArgs(cmdLineArgs, OPTIONS, reportWarnings ? errorReporter : undefined); if (args.goto) { args._.forEach(arg => assert(/^(\w:)?[^:]+(:\d*){0,2}$/.test(arg), localize('gotoValidation', "Arguments in `--goto` mode should be in the format of `FILE(:LINE(:CHARACTER))`."))); } @@ -42,7 +52,9 @@ export function parseMainProcessArgv(processArgv: string[]): ParsedArgs { args = stripAppPath(args) || []; } - return validate(parseArgs(args)); + // If called from CLI, don't report warnings as they are already reported. + let reportWarnings = !process.env['VSCODE_CLI']; + return parseAndValidate(args, reportWarnings); } /** @@ -55,5 +67,5 @@ export function parseCLIProcessArgv(processArgv: string[]): ParsedArgs { args = stripAppPath(args) || []; } - return validate(parseArgs(args)); + return parseAndValidate(args, true); } diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index d909752fe5..52caa265e2 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -16,7 +16,6 @@ import { toLocalISOString } from 'vs/base/common/date'; import { isWindows, isLinux } from 'vs/base/common/platform'; import { getPathFromAmdModule } from 'vs/base/common/amd'; import { URI } from 'vs/base/common/uri'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; // Read this before there's any chance it is overwritten // Related to https://github.com/Microsoft/vscode/issues/30624 @@ -77,7 +76,7 @@ function getCLIPath(execPath: string, appRoot: string, isBuilt: boolean): string export class EnvironmentService implements IEnvironmentService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; get args(): ParsedArgs { return this._args; } @@ -105,9 +104,6 @@ export class EnvironmentService implements IEnvironmentService { return parseUserDataDir(this._args, process); } - @memoize - get webUserDataHome(): URI { return URI.file(parsePathArg(this._args['web-user-data-dir'], process) || this.userDataPath); } - get appNameLong(): string { return product.nameLong; } get appQuality(): string | undefined { return product.quality; } @@ -199,11 +195,6 @@ export class EnvironmentService implements IEnvironmentService { } return URI.file(path.normalize(p)); }); - } else if (s) { - if (/^[^:/?#]+?:\/\//.test(s)) { - return [URI.parse(s)]; - } - return [URI.file(path.normalize(s))]; } return undefined; } @@ -297,7 +288,7 @@ function parseDebugPort(debugArg: string | undefined, debugBrkArg: string | unde return { port, break: brk, debugId }; } -function parsePathArg(arg: string | undefined, process: NodeJS.Process): string | undefined { +export function parsePathArg(arg: string | undefined, process: NodeJS.Process): string | undefined { if (!arg) { return undefined; } diff --git a/src/vs/platform/environment/test/node/environmentService.test.ts b/src/vs/platform/environment/test/node/environmentService.test.ts index 13b60e4273..40ee93229d 100644 --- a/src/vs/platform/environment/test/node/environmentService.test.ts +++ b/src/vs/platform/environment/test/node/environmentService.test.ts @@ -5,13 +5,13 @@ import * as assert from 'assert'; import * as path from 'vs/base/common/path'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { parseExtensionHostPort, parseUserDataDir } from 'vs/platform/environment/node/environmentService'; suite('EnvironmentService', () => { test('parseExtensionHostPort when built', () => { - const parse = (a: string[]) => parseExtensionHostPort(parseArgs(a), true); + const parse = (a: string[]) => parseExtensionHostPort(parseArgs(a, OPTIONS), true); assert.deepEqual(parse([]), { port: null, break: false, debugId: undefined }); assert.deepEqual(parse(['--debugPluginHost']), { port: null, break: false, debugId: undefined }); @@ -28,7 +28,7 @@ suite('EnvironmentService', () => { }); test('parseExtensionHostPort when unbuilt', () => { - const parse = (a: string[]) => parseExtensionHostPort(parseArgs(a), false); + const parse = (a: string[]) => parseExtensionHostPort(parseArgs(a, OPTIONS), false); assert.deepEqual(parse([]), { port: 5870, break: false, debugId: undefined }); assert.deepEqual(parse(['--debugPluginHost']), { port: 5870, break: false, debugId: undefined }); @@ -45,7 +45,7 @@ suite('EnvironmentService', () => { }); test('userDataPath', () => { - const parse = (a: string[], b: { cwd: () => string, env: { [key: string]: string } }) => parseUserDataDir(parseArgs(a), b); + const parse = (a: string[], b: { cwd: () => string, env: { [key: string]: string } }) => parseUserDataDir(parseArgs(a, OPTIONS), b); assert.equal(parse(['--user-data-dir', './dir'], { cwd: () => '/foo', env: {} }), path.resolve('/foo/dir'), 'should use cwd when --user-data-dir is specified'); @@ -55,11 +55,11 @@ suite('EnvironmentService', () => { // https://github.com/microsoft/vscode/issues/78440 test('careful with boolean file names', function () { - let actual = parseArgs(['-r', 'arg.txt']); + let actual = parseArgs(['-r', 'arg.txt'], OPTIONS); assert(actual['reuse-window']); assert.deepEqual(actual._, ['arg.txt']); - actual = parseArgs(['-r', 'true.txt']); + actual = parseArgs(['-r', 'true.txt'], OPTIONS); assert(actual['reuse-window']); assert.deepEqual(actual._, ['true.txt']); }); diff --git a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts index 1be4791613..e3ae633b4e 100644 --- a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts @@ -375,7 +375,7 @@ interface IRawExtensionsReport { export class ExtensionGalleryService implements IExtensionGalleryService { - _serviceBrand: any; + _serviceBrand: undefined; private extensionsGalleryUrl: string | undefined; private extensionsControlUrl: string | undefined; diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index ac5239f4c0..157f7aae98 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -150,7 +150,7 @@ export interface ITranslation { } export interface IExtensionGalleryService { - _serviceBrand: any; + _serviceBrand: undefined; isEnabled(): boolean; query(token: CancellationToken): Promise>; query(options: IQueryOptions, token: CancellationToken): Promise>; @@ -190,7 +190,7 @@ export const INSTALL_ERROR_MALICIOUS = 'malicious'; export const INSTALL_ERROR_INCOMPATIBLE = 'incompatible'; export interface IExtensionManagementService { - _serviceBrand: any; + _serviceBrand: undefined; onInstallExtension: Event; onDidInstallExtension: Event; diff --git a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts index 79f2cb6282..64d6043fcd 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts @@ -77,7 +77,7 @@ export class ExtensionManagementChannel implements IServerChannel { export class ExtensionManagementChannelClient implements IExtensionManagementService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( private readonly channel: IChannel, diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 876729ff15..db428a58e6 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -104,7 +104,7 @@ interface InstallableExtension { export class ExtensionManagementService extends Disposable implements IExtensionManagementService { - _serviceBrand: any; + _serviceBrand: undefined; private systemExtensionsPath: string; private extensionsPath: string; diff --git a/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts b/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts index 681cf39d48..cfb00237a3 100644 --- a/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts +++ b/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import * as os from 'os'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { join } from 'vs/base/common/path'; import { mkdirp, RimRafMode, rimraf } from 'vs/base/node/pfs'; @@ -51,7 +51,7 @@ suite('Extension Gallery Service', () => { test('marketplace machine id', () => { const args = ['--user-data-dir', marketplaceHome]; - const environmentService = new EnvironmentService(parseArgs(args), process.execPath); + const environmentService = new EnvironmentService(parseArgs(args, OPTIONS), process.execPath); return resolveMarketplaceHeaders(pkg.version, environmentService, fileService).then(headers => { assert.ok(isUUID(headers['X-Market-User-Id'])); @@ -61,7 +61,6 @@ suite('Extension Gallery Service', () => { }); }); }); - test('sortByField', () => { // {{SQL CARBON EDIT}} add test let a: { extensionId: string | undefined; diff --git a/src/vs/platform/files/common/fileService.ts b/src/vs/platform/files/common/fileService.ts index 530a97ffc9..035f45207a 100644 --- a/src/vs/platform/files/common/fileService.ts +++ b/src/vs/platform/files/common/fileService.ts @@ -7,7 +7,6 @@ import { Disposable, IDisposable, toDisposable, dispose, DisposableStore } from import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent, ETAG_DISABLED } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { isAbsolutePath, dirname, basename, joinPath, isEqual, isEqualOrParent } from 'vs/base/common/resources'; import { localize } from 'vs/nls'; import { TernarySearchTree } from 'vs/base/common/map'; @@ -21,7 +20,7 @@ import { Schemas } from 'vs/base/common/network'; export class FileService extends Disposable implements IFileService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private readonly BUFFER_SIZE = 64 * 1024; diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 85d33b60ed..9691a29134 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -6,7 +6,7 @@ import { sep } from 'vs/base/common/path'; import { URI } from 'vs/base/common/uri'; import * as glob from 'vs/base/common/glob'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; import { startsWithIgnoreCase } from 'vs/base/common/strings'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -18,7 +18,7 @@ export const IFileService = createDecorator('fileService'); export interface IFileService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; /** * An event that is fired when a file system provider is added or removed diff --git a/src/vs/platform/files/node/diskFileSystemProvider.ts b/src/vs/platform/files/node/diskFileSystemProvider.ts index f9f910af41..916b96cdd6 100644 --- a/src/vs/platform/files/node/diskFileSystemProvider.ts +++ b/src/vs/platform/files/node/diskFileSystemProvider.ts @@ -38,7 +38,7 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro onDidChangeCapabilities: Event = Event.None; - protected _capabilities: FileSystemProviderCapabilities; + protected _capabilities: FileSystemProviderCapabilities | undefined; get capabilities(): FileSystemProviderCapabilities { if (!this._capabilities) { this._capabilities = diff --git a/src/vs/platform/files/node/watcher/nodejs/watcherService.ts b/src/vs/platform/files/node/watcher/nodejs/watcherService.ts index c690225ece..dcf6105c76 100644 --- a/src/vs/platform/files/node/watcher/nodejs/watcherService.ts +++ b/src/vs/platform/files/node/watcher/nodejs/watcherService.ts @@ -13,7 +13,7 @@ import { ThrottledDelayer } from 'vs/base/common/async'; import { join, basename } from 'vs/base/common/path'; export class FileWatcher extends Disposable { - private isDisposed: boolean; + private isDisposed: boolean | undefined; private fileChangesDelayer: ThrottledDelayer = this._register(new ThrottledDelayer(CHANGE_BUFFER_DELAY * 2 /* sync on delay from underlying library */)); private fileChangesBuffer: IDiskFileChange[] = []; @@ -125,4 +125,4 @@ export class FileWatcher extends Disposable { super.dispose(); } -} \ No newline at end of file +} diff --git a/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts b/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts index 0f6eeaf23f..5b74e12e08 100644 --- a/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts +++ b/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts @@ -36,8 +36,8 @@ export class NsfwWatcherService implements IWatcherService { private static readonly FS_EVENT_DELAY = 50; // aggregate and only emit events when changes have stopped for this duration (in ms) private _pathWatchers: { [watchPath: string]: IPathWatcher } = {}; - private _verboseLogging: boolean; - private enospcErrorLogged: boolean; + private _verboseLogging: boolean | undefined; + private enospcErrorLogged: boolean | undefined; private _onWatchEvent = new Emitter(); readonly onWatchEvent = this._onWatchEvent.event; diff --git a/src/vs/platform/files/node/watcher/nsfw/watcherService.ts b/src/vs/platform/files/node/watcher/nsfw/watcherService.ts index a9a36078f1..3b39adca39 100644 --- a/src/vs/platform/files/node/watcher/nsfw/watcherService.ts +++ b/src/vs/platform/files/node/watcher/nsfw/watcherService.ts @@ -12,9 +12,10 @@ import { IWatcherRequest } from 'vs/platform/files/node/watcher/nsfw/watcher'; import { getPathFromAmdModule } from 'vs/base/common/amd'; export class FileWatcher extends Disposable { + private static readonly MAX_RESTARTS = 5; - private service: WatcherChannelClient; + private service: WatcherChannelClient | undefined; private isDisposed: boolean; private restartCounter: number; @@ -77,7 +78,7 @@ export class FileWatcher extends Disposable { setVerboseLogging(verboseLogging: boolean): void { this.verboseLogging = verboseLogging; - if (!this.isDisposed) { + if (!this.isDisposed && this.service) { this.service.setVerboseLogging(verboseLogging); } } @@ -89,7 +90,9 @@ export class FileWatcher extends Disposable { setFolders(folders: IWatcherRequest[]): void { this.folders = folders; - this.service.setRoots(folders); + if (this.service) { + this.service.setRoots(folders); + } } dispose(): void { diff --git a/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts b/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts index fd4bd3dd93..7944b70982 100644 --- a/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts +++ b/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts @@ -37,11 +37,11 @@ export class ChokidarWatcherService implements IWatcherService { private _pollingInterval?: number; private _usePolling?: boolean; - private _verboseLogging: boolean; + private _verboseLogging: boolean | undefined; - private spamCheckStartTime: number; - private spamWarningLogged: boolean; - private enospcErrorLogged: boolean; + private spamCheckStartTime: number | undefined; + private spamWarningLogged: boolean | undefined; + private enospcErrorLogged: boolean | undefined; private _onWatchEvent = new Emitter(); readonly onWatchEvent = this._onWatchEvent.event; @@ -231,7 +231,7 @@ export class ChokidarWatcherService implements IWatcherService { if (undeliveredFileEvents.length === 0) { this.spamWarningLogged = false; this.spamCheckStartTime = now; - } else if (!this.spamWarningLogged && this.spamCheckStartTime + ChokidarWatcherService.EVENT_SPAM_WARNING_THRESHOLD < now) { + } else if (!this.spamWarningLogged && typeof this.spamCheckStartTime === 'number' && this.spamCheckStartTime + ChokidarWatcherService.EVENT_SPAM_WARNING_THRESHOLD < now) { this.spamWarningLogged = true; this.warn(`Watcher is busy catching up with ${undeliveredFileEvents.length} file changes in 60 seconds. Latest changed path is "${event.path}"`); } diff --git a/src/vs/platform/files/node/watcher/unix/watcherService.ts b/src/vs/platform/files/node/watcher/unix/watcherService.ts index b45c186eb3..92b9e77e94 100644 --- a/src/vs/platform/files/node/watcher/unix/watcherService.ts +++ b/src/vs/platform/files/node/watcher/unix/watcherService.ts @@ -16,7 +16,7 @@ export class FileWatcher extends Disposable { private isDisposed: boolean; private restartCounter: number; - private service: WatcherChannelClient; + private service: WatcherChannelClient | undefined; constructor( private folders: IWatcherRequest[], @@ -81,13 +81,18 @@ export class FileWatcher extends Disposable { setVerboseLogging(verboseLogging: boolean): void { this.verboseLogging = verboseLogging; - this.service.setVerboseLogging(verboseLogging); + + if (this.service) { + this.service.setVerboseLogging(verboseLogging); + } } setFolders(folders: IWatcherRequest[]): void { this.folders = folders; - this.service.setRoots(folders); + if (this.service) { + this.service.setRoots(folders); + } } dispose(): void { diff --git a/src/vs/platform/history/common/history.ts b/src/vs/platform/history/common/history.ts index f5e3cd5abf..c082a5b5b7 100644 --- a/src/vs/platform/history/common/history.ts +++ b/src/vs/platform/history/common/history.ts @@ -47,7 +47,7 @@ export function isRecentFile(curr: IRecent): curr is IRecentFile { export interface IHistoryMainService { - _serviceBrand: any; + _serviceBrand: undefined; onRecentlyOpenedChange: CommonEvent; diff --git a/src/vs/platform/history/electron-main/historyMainService.ts b/src/vs/platform/history/electron-main/historyMainService.ts index db5e9dc50f..ab2806962d 100644 --- a/src/vs/platform/history/electron-main/historyMainService.ts +++ b/src/vs/platform/history/electron-main/historyMainService.ts @@ -22,7 +22,6 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { getSimpleWorkspaceLabel } from 'vs/platform/label/common/label'; import { toStoreData, restoreRecentlyOpened, RecentlyOpenedStorageData } from 'vs/platform/history/common/historyStorage'; import { exists } from 'vs/base/node/pfs'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { ILifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; export class HistoryMainService implements IHistoryMainService { @@ -40,7 +39,7 @@ export class HistoryMainService implements IHistoryMainService { private static readonly recentlyOpenedStorageKey = 'openedPathsList'; - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private _onRecentlyOpenedChange = new Emitter(); readonly onRecentlyOpenedChange: CommonEvent = this._onRecentlyOpenedChange.event; diff --git a/src/vs/platform/instantiation/common/instantiation.ts b/src/vs/platform/instantiation/common/instantiation.ts index 49d710c59d..345127cc13 100644 --- a/src/vs/platform/instantiation/common/instantiation.ts +++ b/src/vs/platform/instantiation/common/instantiation.ts @@ -23,39 +23,39 @@ export namespace _util { // --- interfaces ------ export interface IConstructorSignature0 { - new(...services: { _serviceBrand: any; }[]): T; + new(...services: { _serviceBrand: undefined; }[]): T; } export interface IConstructorSignature1 { - new(first: A1, ...services: { _serviceBrand: any; }[]): T; + new(first: A1, ...services: { _serviceBrand: undefined; }[]): T; } export interface IConstructorSignature2 { - new(first: A1, second: A2, ...services: { _serviceBrand: any; }[]): T; + new(first: A1, second: A2, ...services: { _serviceBrand: undefined; }[]): T; } export interface IConstructorSignature3 { - new(first: A1, second: A2, third: A3, ...services: { _serviceBrand: any; }[]): T; + new(first: A1, second: A2, third: A3, ...services: { _serviceBrand: undefined; }[]): T; } export interface IConstructorSignature4 { - new(first: A1, second: A2, third: A3, fourth: A4, ...services: { _serviceBrand: any; }[]): T; + new(first: A1, second: A2, third: A3, fourth: A4, ...services: { _serviceBrand: undefined; }[]): T; } export interface IConstructorSignature5 { - new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, ...services: { _serviceBrand: any; }[]): T; + new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, ...services: { _serviceBrand: undefined; }[]): T; } export interface IConstructorSignature6 { - new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, ...services: { _serviceBrand: any; }[]): T; + new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, ...services: { _serviceBrand: undefined; }[]): T; } export interface IConstructorSignature7 { - new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, ...services: { _serviceBrand: any; }[]): T; + new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, ...services: { _serviceBrand: undefined; }[]): T; } export interface IConstructorSignature8 { - new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, eigth: A8, ...services: { _serviceBrand: any; }[]): T; + new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, eigth: A8, ...services: { _serviceBrand: undefined; }[]): T; } export interface ServicesAccessor { @@ -67,7 +67,7 @@ export const IInstantiationService = createDecorator('ins export interface IInstantiationService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Synchronously creates an instance that is denoted by diff --git a/src/vs/platform/instantiation/common/instantiationService.ts b/src/vs/platform/instantiation/common/instantiationService.ts index ad86a5a3b9..b67aa8d647 100644 --- a/src/vs/platform/instantiation/common/instantiationService.ts +++ b/src/vs/platform/instantiation/common/instantiationService.ts @@ -28,7 +28,7 @@ class CyclicDependencyError extends Error { export class InstantiationService implements IInstantiationService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _services: ServiceCollection; private readonly _strict: boolean; diff --git a/src/vs/platform/instantiation/test/common/instantiationService.test.ts b/src/vs/platform/instantiation/test/common/instantiationService.test.ts index 49a6888fbc..15213916b5 100644 --- a/src/vs/platform/instantiation/test/common/instantiationService.test.ts +++ b/src/vs/platform/instantiation/test/common/instantiationService.test.ts @@ -12,48 +12,48 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; let IService1 = createDecorator('service1'); interface IService1 { - _serviceBrand: any; + _serviceBrand: undefined; c: number; } class Service1 implements IService1 { - _serviceBrand: any; + _serviceBrand: undefined; c = 1; } let IService2 = createDecorator('service2'); interface IService2 { - _serviceBrand: any; + _serviceBrand: undefined; d: boolean; } class Service2 implements IService2 { - _serviceBrand: any; + _serviceBrand: undefined; d = true; } let IService3 = createDecorator('service3'); interface IService3 { - _serviceBrand: any; + _serviceBrand: undefined; s: string; } class Service3 implements IService3 { - _serviceBrand: any; + _serviceBrand: undefined; s = 'farboo'; } let IDependentService = createDecorator('dependentService'); interface IDependentService { - _serviceBrand: any; + _serviceBrand: undefined; name: string; } class DependentService implements IDependentService { - _serviceBrand: any; + _serviceBrand: undefined; constructor(@IService1 service: IService1) { assert.equal(service.c, 1); } @@ -116,7 +116,7 @@ class DependentServiceTarget2 { class ServiceLoop1 implements IService1 { - _serviceBrand: any; + _serviceBrand: undefined; c = 1; constructor(@IService2 s: IService2) { @@ -125,7 +125,7 @@ class ServiceLoop1 implements IService1 { } class ServiceLoop2 implements IService2 { - _serviceBrand: any; + _serviceBrand: undefined; d = true; constructor(@IService1 s: IService1) { @@ -364,7 +364,7 @@ suite('Instantiation Service', () => { let serviceInstanceCount = 0; const CtorCounter = class implements Service1 { - _serviceBrand: any; + _serviceBrand: undefined; c = 1; constructor() { serviceInstanceCount += 1; diff --git a/src/vs/platform/ipc/electron-browser/mainProcessService.ts b/src/vs/platform/ipc/electron-browser/mainProcessService.ts index de03dae639..643af5f74f 100644 --- a/src/vs/platform/ipc/electron-browser/mainProcessService.ts +++ b/src/vs/platform/ipc/electron-browser/mainProcessService.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { Client } from 'vs/base/parts/ipc/electron-browser/ipc.electron-browser'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -12,7 +12,7 @@ export const IMainProcessService = createDecorator('mainPro export interface IMainProcessService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; getChannel(channelName: string): IChannel; @@ -21,7 +21,7 @@ export interface IMainProcessService { export class MainProcessService extends Disposable implements IMainProcessService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private mainProcessConnection: Client; diff --git a/src/vs/platform/ipc/electron-browser/sharedProcessService.ts b/src/vs/platform/ipc/electron-browser/sharedProcessService.ts index f40fc2584e..9a0c78cba8 100644 --- a/src/vs/platform/ipc/electron-browser/sharedProcessService.ts +++ b/src/vs/platform/ipc/electron-browser/sharedProcessService.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Client } from 'vs/base/parts/ipc/common/ipc.net'; import { connect } from 'vs/base/parts/ipc/node/ipc.net'; import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; @@ -14,7 +14,7 @@ export const ISharedProcessService = createDecorator('sha export interface ISharedProcessService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; getChannel(channelName: string): IChannel; @@ -23,7 +23,7 @@ export interface ISharedProcessService { export class SharedProcessService implements ISharedProcessService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private withSharedProcessConnection: Promise>; diff --git a/src/vs/platform/issue/electron-browser/issueService.ts b/src/vs/platform/issue/electron-browser/issueService.ts index f709d07cfd..9764d021a4 100644 --- a/src/vs/platform/issue/electron-browser/issueService.ts +++ b/src/vs/platform/issue/electron-browser/issueService.ts @@ -6,11 +6,10 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IIssueService, IssueReporterData, ProcessExplorerData } from 'vs/platform/issue/node/issue'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class IssueService implements IIssueService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private channel: IChannel; diff --git a/src/vs/platform/issue/electron-main/issueService.ts b/src/vs/platform/issue/electron-main/issueService.ts index 49dd08b60b..297260707c 100644 --- a/src/vs/platform/issue/electron-main/issueService.ts +++ b/src/vs/platform/issue/electron-main/issueService.ts @@ -5,7 +5,7 @@ import { localize } from 'vs/nls'; import * as objects from 'vs/base/common/objects'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { IIssueService, IssueReporterData, IssueReporterFeatures, ProcessExplorerData } from 'vs/platform/issue/node/issue'; import { BrowserWindow, ipcMain, screen, Event, dialog } from 'electron'; import { ILaunchService } from 'vs/platform/launch/electron-main/launchService'; @@ -21,7 +21,7 @@ import { listProcesses } from 'vs/base/node/ps'; const DEFAULT_BACKGROUND_COLOR = '#1E1E1E'; export class IssueService implements IIssueService { - _serviceBrand: any; + _serviceBrand: undefined; _issueWindow: BrowserWindow | null = null; _issueParentWindow: BrowserWindow | null = null; _processExplorerWindow: BrowserWindow | null = null; @@ -372,7 +372,7 @@ export class IssueService implements IIssueService { } function toLauchUrl(pathToHtml: string, windowConfiguration: T): string { - const environment = parseArgs(process.argv); + const environment = parseArgs(process.argv, OPTIONS); const config = objects.assign(environment, windowConfiguration); for (const keyValue of Object.keys(config)) { const key = keyValue as keyof typeof config; diff --git a/src/vs/platform/issue/node/issue.ts b/src/vs/platform/issue/node/issue.ts index a8ec7a3099..70785d5174 100644 --- a/src/vs/platform/issue/node/issue.ts +++ b/src/vs/platform/issue/node/issue.ts @@ -87,7 +87,7 @@ export interface ProcessExplorerData extends WindowData { } export interface IIssueService { - _serviceBrand: any; + _serviceBrand: undefined; openReporter(data: IssueReporterData): Promise; openProcessExplorer(data: ProcessExplorerData): Promise; getSystemStatus(): Promise; diff --git a/src/vs/platform/keybinding/common/abstractKeybindingService.ts b/src/vs/platform/keybinding/common/abstractKeybindingService.ts index 8efea4a2a0..5c0288b3a6 100644 --- a/src/vs/platform/keybinding/common/abstractKeybindingService.ts +++ b/src/vs/platform/keybinding/common/abstractKeybindingService.ts @@ -24,7 +24,7 @@ interface CurrentChord { } export abstract class AbstractKeybindingService extends Disposable implements IKeybindingService { - public _serviceBrand: any; + public _serviceBrand: undefined; protected readonly _onDidUpdateKeybindings: Emitter = this._register(new Emitter()); get onDidUpdateKeybindings(): Event { diff --git a/src/vs/platform/keybinding/common/keybinding.ts b/src/vs/platform/keybinding/common/keybinding.ts index 7b753719ea..5682946aba 100644 --- a/src/vs/platform/keybinding/common/keybinding.ts +++ b/src/vs/platform/keybinding/common/keybinding.ts @@ -41,7 +41,7 @@ export interface IKeyboardEvent { export const IKeybindingService = createDecorator('keybindingService'); export interface IKeybindingService { - _serviceBrand: any; + _serviceBrand: undefined; onDidUpdateKeybindings: Event; diff --git a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts index ddee4b60a8..b1fadfe2e4 100644 --- a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts +++ b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts @@ -15,7 +15,6 @@ import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKe import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; import { INotification, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; function createContext(ctx: any) { return { @@ -132,7 +131,7 @@ suite('AbstractKeybindingService', () => { }; let notificationService: INotificationService = { - _serviceBrand: {} as ServiceIdentifier, + _serviceBrand: undefined, notify: (notification: INotification) => { showMessageCalls.push({ sev: notification.severity, message: notification.message }); return new NoOpNotification(); diff --git a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts index f4b2eefb88..0c1e2111b8 100644 --- a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts +++ b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts @@ -36,7 +36,7 @@ class MockKeybindingContextKey implements IContextKey { export class MockContextKeyService implements IContextKeyService { - public _serviceBrand: any; + public _serviceBrand: undefined; private _keys = new Map>(); public dispose(): void { @@ -69,7 +69,7 @@ export class MockContextKeyService implements IContextKeyService { } export class MockKeybindingService implements IKeybindingService { - public _serviceBrand: any; + public _serviceBrand: undefined; public get onDidUpdateKeybindings(): Event { return Event.None; diff --git a/src/vs/platform/label/common/label.ts b/src/vs/platform/label/common/label.ts index 1009bcd3f2..f4988822c8 100644 --- a/src/vs/platform/label/common/label.ts +++ b/src/vs/platform/label/common/label.ts @@ -14,7 +14,7 @@ import { isEqualOrParent, basename } from 'vs/base/common/resources'; import { endsWith } from 'vs/base/common/strings'; export interface ILabelService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Gets the human readable label for a uri. * If relative is passed returns a label relative to the workspace root that the uri belongs to. diff --git a/src/vs/platform/launch/electron-main/launchService.ts b/src/vs/platform/launch/electron-main/launchService.ts index 33be9edb5e..133e304bf9 100644 --- a/src/vs/platform/launch/electron-main/launchService.ts +++ b/src/vs/platform/launch/electron-main/launchService.ts @@ -8,7 +8,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IURLService } from 'vs/platform/url/common/url'; import { IProcessEnvironment, isMacintosh } from 'vs/base/common/platform'; import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { OpenContext, IWindowSettings } from 'vs/platform/windows/common/windows'; import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; import { whenDeleted } from 'vs/base/node/pfs'; @@ -17,7 +17,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { URI } from 'vs/base/common/uri'; import { BrowserWindow, ipcMain, Event as IpcEvent, app } from 'electron'; import { Event } from 'vs/base/common/event'; -import { hasArgs } from 'vs/platform/environment/node/argv'; import { coalesce } from 'vs/base/common/arrays'; import { IDiagnosticInfoOptions, IDiagnosticInfo, IRemoteDiagnosticInfo, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics'; import { IMainProcessInfo, IWindowInfo } from 'vs/platform/launch/common/launchService'; @@ -53,7 +52,7 @@ function parseOpenUrl(args: ParsedArgs): URI[] { } export interface ILaunchService { - _serviceBrand: any; + _serviceBrand: undefined; start(args: ParsedArgs, userEnv: IProcessEnvironment): Promise; getMainProcessId(): Promise; getMainProcessInfo(): Promise; @@ -94,7 +93,7 @@ export class LaunchChannel implements IServerChannel { export class LaunchChannelClient implements ILaunchService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; constructor(private channel: IChannel) { } @@ -121,7 +120,7 @@ export class LaunchChannelClient implements ILaunchService { export class LaunchService implements ILaunchService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; constructor( @ILogService private readonly logService: ILogService, @@ -173,7 +172,7 @@ export class LaunchService implements ILaunchService { } // Start without file/folder arguments - else if (!hasArgs(args._) && !hasArgs(args['folder-uri']) && !hasArgs(args['file-uri'])) { + else if (!args._.length && !args['folder-uri'] && !args['file-uri']) { let openNewWindow = false; // Force new window diff --git a/src/vs/platform/layout/browser/layoutService.ts b/src/vs/platform/layout/browser/layoutService.ts index 59053d9ef5..cb168dca82 100644 --- a/src/vs/platform/layout/browser/layoutService.ts +++ b/src/vs/platform/layout/browser/layoutService.ts @@ -15,7 +15,7 @@ export interface IDimension { export interface ILayoutService { - _serviceBrand: any; + _serviceBrand: undefined; /** * The dimensions of the container. diff --git a/src/vs/platform/lifecycle/browser/lifecycleService.ts b/src/vs/platform/lifecycle/browser/lifecycleService.ts index 3401a44801..60f7dce6ff 100644 --- a/src/vs/platform/lifecycle/browser/lifecycleService.ts +++ b/src/vs/platform/lifecycle/browser/lifecycleService.ts @@ -3,15 +3,14 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ShutdownReason, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService'; import { localize } from 'vs/nls'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class BrowserLifecycleService extends AbstractLifecycleService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; constructor( @ILogService readonly logService: ILogService diff --git a/src/vs/platform/lifecycle/common/lifecycle.ts b/src/vs/platform/lifecycle/common/lifecycle.ts index de8a6d94ee..266e48d6ab 100644 --- a/src/vs/platform/lifecycle/common/lifecycle.ts +++ b/src/vs/platform/lifecycle/common/lifecycle.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { isThenable } from 'vs/base/common/async'; export const ILifecycleService = createDecorator('lifecycleService'); @@ -123,7 +123,7 @@ export function LifecyclePhaseToString(phase: LifecyclePhase) { */ export interface ILifecycleService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; /** * Value indicates how this window got loaded. @@ -167,7 +167,7 @@ export interface ILifecycleService { export const NullLifecycleService: ILifecycleService = { - _serviceBrand: null as any, + _serviceBrand: undefined, onBeforeShutdown: Event.None, onWillShutdown: Event.None, diff --git a/src/vs/platform/lifecycle/common/lifecycleService.ts b/src/vs/platform/lifecycle/common/lifecycleService.ts index 70d3901da1..b64a7acfb3 100644 --- a/src/vs/platform/lifecycle/common/lifecycleService.ts +++ b/src/vs/platform/lifecycle/common/lifecycleService.ts @@ -9,11 +9,10 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { ILifecycleService, BeforeShutdownEvent, WillShutdownEvent, StartupKind, LifecyclePhase, LifecyclePhaseToString } from 'vs/platform/lifecycle/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; import { mark } from 'vs/base/common/performance'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export abstract class AbstractLifecycleService extends Disposable implements ILifecycleService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; protected readonly _onBeforeShutdown = this._register(new Emitter()); readonly onBeforeShutdown: Event = this._onBeforeShutdown.event; diff --git a/src/vs/platform/lifecycle/electron-browser/lifecycleService.ts b/src/vs/platform/lifecycle/electron-browser/lifecycleService.ts index 22260de1df..c0cf5edbc6 100644 --- a/src/vs/platform/lifecycle/electron-browser/lifecycleService.ts +++ b/src/vs/platform/lifecycle/electron-browser/lifecycleService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { toErrorMessage } from 'vs/base/common/errorMessage'; -import { ShutdownReason, StartupKind, handleVetos, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { ShutdownReason, StartupKind, handleVetos } from 'vs/platform/lifecycle/common/lifecycle'; import { IStorageService, StorageScope, WillSaveStateReason } from 'vs/platform/storage/common/storage'; import { ipcRenderer as ipc } from 'electron'; import { IWindowService } from 'vs/platform/windows/common/windows'; @@ -12,13 +12,12 @@ import { ILogService } from 'vs/platform/log/common/log'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { onUnexpectedError } from 'vs/base/common/errors'; import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class LifecycleService extends AbstractLifecycleService { private static readonly LAST_SHUTDOWN_REASON_KEY = 'lifecyle.lastShutdownReason'; - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private shutdownReason: ShutdownReason; diff --git a/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts b/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts index 171409acf8..86a1006bf7 100644 --- a/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts +++ b/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts @@ -7,7 +7,7 @@ import { ipcMain as ipc, app } from 'electron'; import { ILogService } from 'vs/platform/log/common/log'; import { IStateService } from 'vs/platform/state/common/state'; import { Event, Emitter } from 'vs/base/common/event'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; import { handleVetos } from 'vs/platform/lifecycle/common/lifecycle'; import { isMacintosh, isWindows } from 'vs/base/common/platform'; @@ -40,7 +40,7 @@ export interface ShutdownEvent { export interface ILifecycleService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; /** * Will be true if the program was restarted (e.g. due to explicit request or update). @@ -131,7 +131,7 @@ export const enum LifecycleMainPhase { export class LifecycleService extends Disposable implements ILifecycleService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private static readonly QUIT_FROM_RESTART_MARKER = 'quit.from.restart'; // use a marker to find out if the session was restarted @@ -139,10 +139,10 @@ export class LifecycleService extends Disposable implements ILifecycleService { private oneTimeListenerTokenGenerator = 0; private windowCounter = 0; - private pendingQuitPromise: Promise | null; - private pendingQuitPromiseResolve: { (veto: boolean): void } | null; + private pendingQuitPromise: Promise | null = null; + private pendingQuitPromiseResolve: { (veto: boolean): void } | null = null; - private pendingWillShutdownPromise: Promise | null; + private pendingWillShutdownPromise: Promise | null = null; private _quitRequested = false; get quitRequested(): boolean { return this._quitRequested; } diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 84e59b5824..3469c27f9c 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -25,9 +25,9 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { attachListStyler, computeStyles, defaultListStyles } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys'; -import { ObjectTree, IObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTree'; +import { ObjectTree, IObjectTreeOptions, ICompressibleTreeRenderer } from 'vs/base/browser/ui/tree/objectTree'; import { ITreeEvent, ITreeRenderer, IAsyncDataSource, IDataSource, ITreeMouseEvent } from 'vs/base/browser/ui/tree/tree'; -import { AsyncDataTree, IAsyncDataTreeOptions } from 'vs/base/browser/ui/tree/asyncDataTree'; +import { AsyncDataTree, IAsyncDataTreeOptions, CompressibleAsyncDataTree, ITreeCompressionDelegate } from 'vs/base/browser/ui/tree/asyncDataTree'; import { DataTree, IDataTreeOptions } from 'vs/base/browser/ui/tree/dataTree'; import { IKeyboardNavigationEventFilter, IAbstractTreeOptions, RenderIndentGuides } from 'vs/base/browser/ui/tree/abstractTree'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; @@ -38,7 +38,7 @@ export const IListService = createDecorator('listService'); export interface IListService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Returns the currently focused list widget if any. @@ -53,7 +53,7 @@ interface IRegisteredList { export class ListService implements IListService { - _serviceBrand: any; + _serviceBrand: undefined; private lists: IRegisteredList[] = []; private _lastFocusedWidget: ListWidget | undefined = undefined; @@ -245,6 +245,7 @@ export class WorkbenchList extends List { private _useAltAsMultipleSelectionModifier: boolean; constructor( + user: string, container: HTMLElement, delegate: IListVirtualDelegate, renderers: IListRenderer[], @@ -258,7 +259,7 @@ export class WorkbenchList extends List { const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : getHorizontalScrollingSetting(configurationService); const [workbenchListOptions, workbenchListOptionsDisposable] = toWorkbenchListOptions(options, configurationService, keybindingService); - super(container, delegate, renderers, + super(user, container, delegate, renderers, { keyboardSupport: false, styleController: new DefaultStyleController(getSharedListStyleSheet()), @@ -326,6 +327,7 @@ export class WorkbenchPagedList extends PagedList { private _useAltAsMultipleSelectionModifier: boolean; constructor( + user: string, container: HTMLElement, delegate: IListVirtualDelegate, renderers: IPagedRenderer[], @@ -338,7 +340,7 @@ export class WorkbenchPagedList extends PagedList { ) { const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : getHorizontalScrollingSetting(configurationService); const [workbenchListOptions, workbenchListOptionsDisposable] = toWorkbenchListOptions(options, configurationService, keybindingService); - super(container, delegate, renderers, + super(user, container, delegate, renderers, { keyboardSupport: false, styleController: new DefaultStyleController(getSharedListStyleSheet()), @@ -679,7 +681,7 @@ export class TreeResourceNavigator2 extends Disposable { readonly onDidOpenResource: Event> = this._onDidOpenResource.event; constructor( - private tree: WorkbenchObjectTree | WorkbenchDataTree | WorkbenchAsyncDataTree, + private tree: WorkbenchObjectTree | WorkbenchDataTree | WorkbenchAsyncDataTree | WorkbenchCompressibleAsyncDataTree, options?: IResourceResultsNavigationOptions2 ) { super(); @@ -785,6 +787,7 @@ export class WorkbenchObjectTree, TFilterData = void> get useAltAsMultipleSelectionModifier(): boolean { return this.internals.useAltAsMultipleSelectionModifier; } constructor( + user: string, container: HTMLElement, delegate: IListVirtualDelegate, renderers: ITreeRenderer[], @@ -797,7 +800,7 @@ export class WorkbenchObjectTree, TFilterData = void> @IAccessibilityService accessibilityService: IAccessibilityService ) { const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, themeService, configurationService, keybindingService, accessibilityService); - super(container, delegate, renderers, treeOptions); + super(user, container, delegate, renderers, treeOptions); this.disposables.push(disposable); this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, contextKeyService, listService, themeService, configurationService, accessibilityService); this.disposables.push(this.internals); @@ -811,6 +814,7 @@ export class WorkbenchDataTree extends DataTree, renderers: ITreeRenderer[], @@ -824,7 +828,7 @@ export class WorkbenchDataTree extends DataTree extends Async get useAltAsMultipleSelectionModifier(): boolean { return this.internals.useAltAsMultipleSelectionModifier; } constructor( + user: string, container: HTMLElement, delegate: IListVirtualDelegate, renderers: ITreeRenderer[], @@ -851,7 +856,36 @@ export class WorkbenchAsyncDataTree extends Async @IAccessibilityService accessibilityService: IAccessibilityService ) { const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, themeService, configurationService, keybindingService, accessibilityService); - super(container, delegate, renderers, dataSource, treeOptions); + super(user, container, delegate, renderers, dataSource, treeOptions); + this.disposables.push(disposable); + this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, contextKeyService, listService, themeService, configurationService, accessibilityService); + this.disposables.push(this.internals); + } +} + +export class WorkbenchCompressibleAsyncDataTree extends CompressibleAsyncDataTree { + + private internals: WorkbenchTreeInternals; + get contextKeyService(): IContextKeyService { return this.internals.contextKeyService; } + get useAltAsMultipleSelectionModifier(): boolean { return this.internals.useAltAsMultipleSelectionModifier; } + + constructor( + user: string, + container: HTMLElement, + virtualDelegate: IListVirtualDelegate, + compressionDelegate: ITreeCompressionDelegate, + renderers: ICompressibleTreeRenderer[], + dataSource: IAsyncDataSource, + options: IAsyncDataTreeOptions, + @IContextKeyService contextKeyService: IContextKeyService, + @IListService listService: IListService, + @IThemeService themeService: IThemeService, + @IConfigurationService configurationService: IConfigurationService, + @IKeybindingService keybindingService: IKeybindingService, + @IAccessibilityService accessibilityService: IAccessibilityService + ) { + const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, themeService, configurationService, keybindingService, accessibilityService); + super(user, container, virtualDelegate, compressionDelegate, renderers, dataSource, treeOptions); this.disposables.push(disposable); this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, contextKeyService, listService, themeService, configurationService, accessibilityService); this.disposables.push(this.internals); @@ -923,7 +957,7 @@ class WorkbenchTreeInternals { private disposables: IDisposable[] = []; constructor( - tree: WorkbenchObjectTree | WorkbenchDataTree | WorkbenchAsyncDataTree, + tree: WorkbenchObjectTree | WorkbenchDataTree | WorkbenchAsyncDataTree | WorkbenchCompressibleAsyncDataTree, options: IAbstractTreeOptions | IAsyncDataTreeOptions, getAutomaticKeyboardNavigation: () => boolean | undefined, @IContextKeyService contextKeyService: IContextKeyService, diff --git a/src/vs/platform/localizations/common/localizations.ts b/src/vs/platform/localizations/common/localizations.ts index f8a5aa5920..7a6240eacb 100644 --- a/src/vs/platform/localizations/common/localizations.ts +++ b/src/vs/platform/localizations/common/localizations.ts @@ -26,7 +26,7 @@ export const enum LanguageType { export const ILocalizationsService = createDecorator('localizationsService'); export interface ILocalizationsService { - _serviceBrand: any; + _serviceBrand: undefined; readonly onDidLanguagesChange: Event; getLanguageIds(type?: LanguageType): Promise; diff --git a/src/vs/platform/localizations/electron-browser/localizationsService.ts b/src/vs/platform/localizations/electron-browser/localizationsService.ts index c305e99798..674a9addf9 100644 --- a/src/vs/platform/localizations/electron-browser/localizationsService.ts +++ b/src/vs/platform/localizations/electron-browser/localizationsService.ts @@ -7,11 +7,10 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { Event } from 'vs/base/common/event'; import { ILocalizationsService, LanguageType } from 'vs/platform/localizations/common/localizations'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class LocalizationsService implements ILocalizationsService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private channel: IChannel; diff --git a/src/vs/platform/localizations/node/localizations.ts b/src/vs/platform/localizations/node/localizations.ts index 609a286b9e..25144e562e 100644 --- a/src/vs/platform/localizations/node/localizations.ts +++ b/src/vs/platform/localizations/node/localizations.ts @@ -34,7 +34,7 @@ if (product.quality !== 'stable') { export class LocalizationsService extends Disposable implements ILocalizationsService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly cache: LanguagePacksCache; diff --git a/src/vs/platform/log/common/bufferLog.ts b/src/vs/platform/log/common/bufferLog.ts index 31134f4d35..ce1d7497d1 100644 --- a/src/vs/platform/log/common/bufferLog.ts +++ b/src/vs/platform/log/common/bufferLog.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ILogService, LogLevel, AbstractLogService } from 'vs/platform/log/common/log'; +import { ILogService, LogLevel, AbstractLogService, DEFAULT_LOG_LEVEL } from 'vs/platform/log/common/log'; interface ILog { level: LogLevel; @@ -24,12 +24,13 @@ function getLogFunction(logger: ILogService, level: LogLevel): Function { export class BufferLogService extends AbstractLogService implements ILogService { - _serviceBrand: any; + _serviceBrand: undefined; private buffer: ILog[] = []; private _logger: ILogService | undefined = undefined; - constructor() { + constructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) { super(); + this.setLevel(logLevel); this._register(this.onDidChangeLogLevel(level => { if (this._logger) { this._logger.setLevel(level); @@ -86,4 +87,4 @@ export class BufferLogService extends AbstractLogService implements ILogService this._logger.dispose(); } } -} \ No newline at end of file +} diff --git a/src/vs/platform/log/common/fileLogService.ts b/src/vs/platform/log/common/fileLogService.ts index 0301f322cf..8e4edf4772 100644 --- a/src/vs/platform/log/common/fileLogService.ts +++ b/src/vs/platform/log/common/fileLogService.ts @@ -8,12 +8,16 @@ import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { Queue } from 'vs/base/common/async'; import { VSBuffer } from 'vs/base/common/buffer'; +import { dirname, joinPath, basename } from 'vs/base/common/resources'; + +const MAX_FILE_SIZE = 1024 * 1024 * 5; export class FileLogService extends AbstractLogService implements ILogService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly queue: Queue; + private backupIndex: number = 1; constructor( private readonly name: string, @@ -81,6 +85,10 @@ export class FileLogService extends AbstractLogService implements ILogService { private _log(level: LogLevel, message: string): void { this.queue.queue(async () => { let content = await this.loadContent(); + if (content.length > MAX_FILE_SIZE) { + await this.fileService.writeFile(this.getBackupResource(), VSBuffer.fromString(content)); + content = ''; + } content += `[${this.getCurrentTimestamp()}] [${this.name}] [${this.stringifyLogLevel(level)}] ${message}\n`; await this.fileService.writeFile(this.resource, VSBuffer.fromString(content)); }); @@ -93,6 +101,11 @@ export class FileLogService extends AbstractLogService implements ILogService { return `${currentTime.getFullYear()}-${toTwoDigits(currentTime.getMonth() + 1)}-${toTwoDigits(currentTime.getDate())} ${toTwoDigits(currentTime.getHours())}:${toTwoDigits(currentTime.getMinutes())}:${toTwoDigits(currentTime.getSeconds())}.${toThreeDigits(currentTime.getMilliseconds())}`; } + private getBackupResource(): URI { + this.backupIndex = this.backupIndex > 5 ? 1 : this.backupIndex; + return joinPath(dirname(this.resource), `${basename(this.resource)}_${this.backupIndex++}`); + } + private async loadContent(): Promise { try { const content = await this.fileService.readFile(this.resource); diff --git a/src/vs/platform/log/common/log.ts b/src/vs/platform/log/common/log.ts index 25a67c3b41..86cedcca7f 100644 --- a/src/vs/platform/log/common/log.ts +++ b/src/vs/platform/log/common/log.ts @@ -28,7 +28,7 @@ export enum LogLevel { export const DEFAULT_LOG_LEVEL: LogLevel = LogLevel.Info; export interface ILogService extends IDisposable { - _serviceBrand: any; + _serviceBrand: undefined; onDidChangeLogLevel: Event; getLevel(): LogLevel; @@ -61,7 +61,7 @@ export abstract class AbstractLogService extends Disposable { export class ConsoleLogMainService extends AbstractLogService implements ILogService { - _serviceBrand: any; + _serviceBrand: undefined; private useColors: boolean; constructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) { @@ -137,7 +137,7 @@ export class ConsoleLogMainService extends AbstractLogService implements ILogSer export class ConsoleLogService extends AbstractLogService implements ILogService { - _serviceBrand: any; + _serviceBrand: undefined; constructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) { super(); @@ -184,7 +184,7 @@ export class ConsoleLogService extends AbstractLogService implements ILogService } export class MultiplexLogService extends AbstractLogService implements ILogService { - _serviceBrand: any; + _serviceBrand: undefined; constructor(private readonly logServices: ReadonlyArray) { super(); @@ -244,7 +244,7 @@ export class MultiplexLogService extends AbstractLogService implements ILogServi } export class DelegatedLogService extends Disposable implements ILogService { - _serviceBrand: any; + _serviceBrand: undefined; constructor(private logService: ILogService) { super(); @@ -289,7 +289,7 @@ export class DelegatedLogService extends Disposable implements ILogService { } export class NullLogService implements ILogService { - _serviceBrand: any; + _serviceBrand: undefined; readonly onDidChangeLogLevel: Event = new Emitter().event; setLevel(level: LogLevel): void { } getLevel(): LogLevel { return LogLevel.Info; } diff --git a/src/vs/platform/log/common/logIpc.ts b/src/vs/platform/log/common/logIpc.ts index 05fbb23eec..967d08b78b 100644 --- a/src/vs/platform/log/common/logIpc.ts +++ b/src/vs/platform/log/common/logIpc.ts @@ -46,7 +46,7 @@ export class LogLevelSetterChannelClient { } export class FollowerLogService extends DelegatedLogService implements ILogService { - _serviceBrand: any; + _serviceBrand: undefined; constructor(private master: LogLevelSetterChannelClient, logService: ILogService) { super(logService); diff --git a/src/vs/platform/log/node/spdlogService.ts b/src/vs/platform/log/node/spdlogService.ts index ca02c8c3ac..e64d46a5d2 100644 --- a/src/vs/platform/log/node/spdlogService.ts +++ b/src/vs/platform/log/node/spdlogService.ts @@ -44,7 +44,7 @@ function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string): v export class SpdLogService extends AbstractLogService implements ILogService { - _serviceBrand: any; + _serviceBrand: undefined; private buffer: ILog[] = []; private _loggerCreationPromise: Promise | undefined = undefined; diff --git a/src/vs/platform/markers/common/markerService.ts b/src/vs/platform/markers/common/markerService.ts index 0bbbd4e289..a574f68767 100644 --- a/src/vs/platform/markers/common/markerService.ts +++ b/src/vs/platform/markers/common/markerService.ts @@ -121,7 +121,7 @@ class MarkerStats implements MarkerStatistics { export class MarkerService implements IMarkerService { - _serviceBrand: any; + _serviceBrand: undefined; private _onMarkerChanged = new Emitter(); private _onMarkerChangedEvent: Event = Event.debounce(this._onMarkerChanged.event, MarkerService._debouncer, 0); diff --git a/src/vs/platform/markers/common/markers.ts b/src/vs/platform/markers/common/markers.ts index d095685d72..117c7edbe8 100644 --- a/src/vs/platform/markers/common/markers.ts +++ b/src/vs/platform/markers/common/markers.ts @@ -10,7 +10,7 @@ import { localize } from 'vs/nls'; import Severity from 'vs/base/common/severity'; export interface IMarkerService { - _serviceBrand: any; + _serviceBrand: undefined; getStatistics(): MarkerStatistics; diff --git a/src/vs/platform/menubar/electron-browser/menubarService.ts b/src/vs/platform/menubar/electron-browser/menubarService.ts index 941c8df81e..f305702a7e 100644 --- a/src/vs/platform/menubar/electron-browser/menubarService.ts +++ b/src/vs/platform/menubar/electron-browser/menubarService.ts @@ -6,11 +6,10 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IMenubarService, IMenubarData } from 'vs/platform/menubar/node/menubar'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class MenubarService implements IMenubarService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private channel: IChannel; diff --git a/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts index 4b8bc6737b..1dafdd4c5f 100644 --- a/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -13,7 +13,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IUpdateService, StateType } from 'vs/platform/update/common/update'; import product from 'vs/platform/product/node/product'; import { RunOnceScheduler } from 'vs/base/common/async'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ILogService } from 'vs/platform/log/common/log'; import { mnemonicMenuLabel as baseMnemonicLabel } from 'vs/base/common/labels'; import { IWindowsMainService, IWindowsCountChangedEvent } from 'vs/platform/windows/electron-main/windows'; import { IHistoryMainService } from 'vs/platform/history/common/history'; @@ -62,14 +62,14 @@ export class Menubar { constructor( @IUpdateService private readonly updateService: IUpdateService, - @IInstantiationService instantiationService: IInstantiationService, @IConfigurationService private readonly configurationService: IConfigurationService, @IWindowsMainService private readonly windowsMainService: IWindowsMainService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IHistoryMainService private readonly historyMainService: IHistoryMainService, @IStateService private readonly stateService: IStateService, - @ILifecycleService private readonly lifecycleService: ILifecycleService + @ILifecycleService private readonly lifecycleService: ILifecycleService, + @ILogService private readonly logService: ILogService ) { this.menuUpdater = new RunOnceScheduler(() => this.doUpdateMenu(), 0); @@ -118,36 +118,41 @@ export class Menubar { this.fallbackMenuHandlers['workbench.action.clearRecentFiles'] = () => this.historyMainService.clearRecentlyOpened(); // Help Menu Items - if (product.twitterUrl) { - this.fallbackMenuHandlers['workbench.action.openTwitterUrl'] = () => this.openUrl(product.twitterUrl, 'openTwitterUrl'); + const twitterUrl = product.twitterUrl; + if (twitterUrl) { + this.fallbackMenuHandlers['workbench.action.openTwitterUrl'] = () => this.openUrl(twitterUrl, 'openTwitterUrl'); } - if (product.requestFeatureUrl) { - this.fallbackMenuHandlers['workbench.action.openRequestFeatureUrl'] = () => this.openUrl(product.requestFeatureUrl, 'openUserVoiceUrl'); + const requestFeatureUrl = product.requestFeatureUrl; + if (requestFeatureUrl) { + this.fallbackMenuHandlers['workbench.action.openRequestFeatureUrl'] = () => this.openUrl(requestFeatureUrl, 'openUserVoiceUrl'); } - if (product.reportIssueUrl) { - this.fallbackMenuHandlers['workbench.action.openIssueReporter'] = () => this.openUrl(product.reportIssueUrl, 'openReportIssues'); + const reportIssueUrl = product.reportIssueUrl; + if (reportIssueUrl) { + this.fallbackMenuHandlers['workbench.action.openIssueReporter'] = () => this.openUrl(reportIssueUrl, 'openReportIssues'); } - if (product.licenseUrl) { + const licenseUrl = product.licenseUrl; + if (licenseUrl) { this.fallbackMenuHandlers['workbench.action.openLicenseUrl'] = () => { if (language) { - const queryArgChar = product.licenseUrl.indexOf('?') > 0 ? '&' : '?'; - this.openUrl(`${product.licenseUrl}${queryArgChar}lang=${language}`, 'openLicenseUrl'); + const queryArgChar = licenseUrl.indexOf('?') > 0 ? '&' : '?'; + this.openUrl(`${licenseUrl}${queryArgChar}lang=${language}`, 'openLicenseUrl'); } else { - this.openUrl(product.licenseUrl, 'openLicenseUrl'); + this.openUrl(licenseUrl, 'openLicenseUrl'); } }; } - if (product.privacyStatementUrl) { + const privacyStatementUrl = product.privacyStatementUrl; + if (privacyStatementUrl && licenseUrl) { this.fallbackMenuHandlers['workbench.action.openPrivacyStatementUrl'] = () => { if (language) { - const queryArgChar = product.licenseUrl.indexOf('?') > 0 ? '&' : '?'; - this.openUrl(`${product.privacyStatementUrl}${queryArgChar}lang=${language}`, 'openPrivacyStatement'); + const queryArgChar = licenseUrl.indexOf('?') > 0 ? '&' : '?'; + this.openUrl(`${privacyStatementUrl}${queryArgChar}lang=${language}`, 'openPrivacyStatement'); } else { - this.openUrl(product.privacyStatementUrl, 'openPrivacyStatement'); + this.openUrl(privacyStatementUrl, 'openPrivacyStatement'); } }; } @@ -723,6 +728,8 @@ export class Menubar { } if (activeWindow) { + this.logService.trace('menubar#runActionInRenderer', invocation); + if (isMacintosh && !this.environmentService.isBuilt && !activeWindow.isReady) { if ((invocation.type === 'commandId' && invocation.commandId === 'workbench.action.toggleDevTools') || (invocation.type !== 'commandId' && invocation.userSettingsLabel === 'alt+cmd+i')) { // prevent this action from running twice on macOS (https://github.com/Microsoft/vscode/issues/62719) @@ -733,10 +740,12 @@ export class Menubar { } if (invocation.type === 'commandId') { - this.windowsMainService.sendToFocused('vscode:runAction', { id: invocation.commandId, from: 'menu' } as IRunActionInWindowRequest); + activeWindow.sendWhenReady('vscode:runAction', { id: invocation.commandId, from: 'menu' } as IRunActionInWindowRequest); } else { - this.windowsMainService.sendToFocused('vscode:runKeybinding', { userSettingsLabel: invocation.userSettingsLabel } as IRunKeybindingInWindowRequest); + activeWindow.sendWhenReady('vscode:runKeybinding', { userSettingsLabel: invocation.userSettingsLabel } as IRunKeybindingInWindowRequest); } + } else { + this.logService.trace('menubar#runActionInRenderer: no active window found', invocation); } } diff --git a/src/vs/platform/menubar/electron-main/menubarService.ts b/src/vs/platform/menubar/electron-main/menubarService.ts index 0250c1bf86..f139b522db 100644 --- a/src/vs/platform/menubar/electron-main/menubarService.ts +++ b/src/vs/platform/menubar/electron-main/menubarService.ts @@ -9,7 +9,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; export class MenubarService implements IMenubarService { - _serviceBrand: any; + _serviceBrand: undefined; private _menubar: Menubar; diff --git a/src/vs/platform/menubar/node/menubar.ts b/src/vs/platform/menubar/node/menubar.ts index 0cf64720dd..36e3d6b617 100644 --- a/src/vs/platform/menubar/node/menubar.ts +++ b/src/vs/platform/menubar/node/menubar.ts @@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri'; export const IMenubarService = createDecorator('menubarService'); export interface IMenubarService { - _serviceBrand: any; + _serviceBrand: undefined; updateMenubar(windowId: number, menuData: IMenubarData): Promise; } diff --git a/src/vs/platform/notification/common/notification.ts b/src/vs/platform/notification/common/notification.ts index 4a487dfaa0..7de3357ae9 100644 --- a/src/vs/platform/notification/common/notification.ts +++ b/src/vs/platform/notification/common/notification.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import BaseSeverity from 'vs/base/common/severity'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IAction } from 'vs/base/common/actions'; import { Event, Emitter } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -234,7 +234,7 @@ export interface IStatusMessageOptions { */ export interface INotificationService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; /** * Show the provided notification to the user. The returned `INotificationHandle` diff --git a/src/vs/platform/notification/test/common/testNotificationService.ts b/src/vs/platform/notification/test/common/testNotificationService.ts index 9a00472d7c..7c38c1de76 100644 --- a/src/vs/platform/notification/test/common/testNotificationService.ts +++ b/src/vs/platform/notification/test/common/testNotificationService.ts @@ -8,7 +8,7 @@ import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; export class TestNotificationService implements INotificationService { - _serviceBrand: any; + _serviceBrand: undefined; private static readonly NO_OP: INotificationHandle = new NoOpNotification(); diff --git a/src/vs/platform/opener/common/opener.ts b/src/vs/platform/opener/common/opener.ts index e3abbd35c9..fa40e7a678 100644 --- a/src/vs/platform/opener/common/opener.ts +++ b/src/vs/platform/opener/common/opener.ts @@ -20,7 +20,7 @@ export interface IValidator { export interface IOpenerService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Register a participant that can handle the open() call. diff --git a/src/vs/platform/product/browser/product.ts b/src/vs/platform/product/browser/product.ts new file mode 100644 index 0000000000..2370c9d615 --- /dev/null +++ b/src/vs/platform/product/browser/product.ts @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IProductConfiguration } from 'vs/platform/product/common/product'; +import { assign } from 'vs/base/common/objects'; + +// Built time configuration (do NOT modify) +const product = { /*BUILD->INSERT_PRODUCT_CONFIGURATION*/ } as IProductConfiguration; + +// Running out of sources +if (Object.keys(product).length === 0) { + assign(product, { + version: '1.39.0-dev', + nameLong: 'Visual Studio Code Web Dev', + nameShort: 'VSCode Web Dev' + }); +} + +export default product; diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts index 639b35ccc1..40af9658f4 100644 --- a/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -14,83 +14,100 @@ export interface IProductService extends Readonly { } export interface IProductConfiguration { - version: string; - nameShort: string; - nameLong: string; - readonly applicationName: string; - readonly win32AppId: string; - readonly win32x64AppId: string; - readonly win32UserAppId: string; - readonly win32x64UserAppId: string; - readonly win32AppUserModelId: string; - readonly win32MutexName: string; - readonly darwinBundleIdentifier: string; - readonly urlProtocol: string; - dataFolderName: string; - readonly downloadUrl: string; - readonly updateUrl?: string; + readonly version: string; + readonly date?: string; readonly quality?: string; - readonly target?: string; readonly commit?: string; + + readonly nameShort: string; + readonly nameLong: string; + + readonly win32AppUserModelId?: string; + readonly win32MutexName?: string; + readonly applicationName: string; + + readonly urlProtocol: string; + readonly dataFolderName: string; + + readonly downloadUrl?: string; + readonly updateUrl?: string; + readonly target?: string; + readonly settingsSearchBuildId?: number; readonly settingsSearchUrl?: string; + readonly experimentsUrl?: string; - readonly date: string; + readonly extensionsGallery?: { readonly serviceUrl: string; readonly itemUrl: string; readonly controlUrl: string; readonly recommendationsUrl: string; }; - readonly extensionTips: { [id: string]: string; }; + + readonly extensionTips?: { [id: string]: string; }; + readonly extensionImportantTips?: { [id: string]: { name: string; pattern: string; isExtensionPack?: boolean }; }; + readonly exeBasedExtensionTips?: { [id: string]: IExeBasedExtensionTip; }; + readonly extensionKeywords?: { [extension: string]: readonly string[]; }; + readonly keymapExtensionTips?: readonly string[]; + readonly recommendedExtensions: string[]; // {{SQL CARBON EDIT}} readonly recommendedExtensionsByScenario: { [area: string]: Array }; // {{SQL CARBON EDIT}} readonly vscodeVersion: string; // {{SQL CARBON EDIT}} add vscode version readonly gettingStartedUrl: string; // {SQL CARBON EDIT} - readonly extensionImportantTips: { [id: string]: { name: string; pattern: string; isExtensionPack?: boolean }; }; - readonly exeBasedExtensionTips: { [id: string]: IExeBasedExtensionTip; }; - readonly extensionKeywords: { [extension: string]: readonly string[]; }; - readonly extensionAllowedProposedApi: readonly string[]; - readonly keymapExtensionTips: readonly string[]; - readonly crashReporter: { + + readonly crashReporter?: { readonly companyName: string; readonly productName: string; }; - readonly welcomePage: string; - readonly enableTelemetry: boolean; - readonly aiConfig: { + + readonly welcomePage?: string; + + readonly enableTelemetry?: boolean; + readonly aiConfig?: { readonly asimovKey: string; }; - readonly sendASmile: { + + readonly sendASmile?: { readonly reportIssueUrl: string, readonly requestFeatureUrl: string }; - readonly documentationUrl: string; - readonly releaseNotesUrl: string; - readonly keyboardShortcutsUrlMac: string; - readonly keyboardShortcutsUrlLinux: string; - readonly keyboardShortcutsUrlWin: string; - readonly introductoryVideosUrl: string; - readonly tipsAndTricksUrl: string; - readonly newsletterSignupUrl: string; - readonly twitterUrl: string; - readonly requestFeatureUrl: string; - readonly reportIssueUrl: string; - readonly licenseUrl: string; - readonly privacyStatementUrl: string; - readonly telemetryOptOutUrl: string; - readonly npsSurveyUrl: string; - readonly surveys: readonly ISurveyData[]; - readonly checksums: { [path: string]: string; }; - readonly checksumFailMoreInfoUrl: string; - readonly hockeyApp: { + + readonly documentationUrl?: string; + readonly releaseNotesUrl?: string; + readonly keyboardShortcutsUrlMac?: string; + readonly keyboardShortcutsUrlLinux?: string; + readonly keyboardShortcutsUrlWin?: string; + readonly introductoryVideosUrl?: string; + readonly tipsAndTricksUrl?: string; + readonly newsletterSignupUrl?: string; + readonly twitterUrl?: string; + readonly requestFeatureUrl?: string; + readonly reportIssueUrl?: string; + readonly licenseUrl?: string; + readonly privacyStatementUrl?: string; + readonly telemetryOptOutUrl?: string; + + readonly npsSurveyUrl?: string; + readonly surveys?: readonly ISurveyData[]; + + readonly checksums?: { [path: string]: string; }; + readonly checksumFailMoreInfoUrl?: string; + + readonly hockeyApp?: { readonly 'win32-ia32': string; readonly 'win32-x64': string; readonly 'linux-x64': string; readonly 'darwin': string; }; + readonly portable?: string; + readonly uiExtensions?: readonly string[]; + readonly extensionAllowedProposedApi?: readonly string[]; + + readonly msftInternalDomains?: string[]; + readonly linkProtectionTrustedDomains?: readonly string[]; } export interface IExeBasedExtensionTip { diff --git a/src/vs/platform/product/node/product.ts b/src/vs/platform/product/node/product.ts index 51de6b2f06..c3a295ebef 100644 --- a/src/vs/platform/product/node/product.ts +++ b/src/vs/platform/product/node/product.ts @@ -7,17 +7,22 @@ import * as path from 'vs/base/common/path'; import { getPathFromAmdModule } from 'vs/base/common/amd'; import { IProductConfiguration } from 'vs/platform/product/common/product'; import pkg from 'vs/platform/product/node/package'; +import { assign } from 'vs/base/common/objects'; const rootPath = path.dirname(getPathFromAmdModule(require, '')); const productJsonPath = path.join(rootPath, 'product.json'); const product = require.__$__nodeRequire(productJsonPath) as IProductConfiguration; if (process.env['VSCODE_DEV']) { - product.nameShort += ' Dev'; - product.nameLong += ' Dev'; - product.dataFolderName += '-dev'; + assign(product, { + nameShort: `${product.nameShort} Dev`, + nameLong: `${product.nameLong} Dev`, + dataFolderName: `${product.dataFolderName}-dev` + }); } -product.version = pkg.version; +assign(product, { + version: pkg.version +}); export default product; diff --git a/src/vs/platform/progress/common/progress.ts b/src/vs/platform/progress/common/progress.ts index dcf4d7ca42..026ea96409 100644 --- a/src/vs/platform/progress/common/progress.ts +++ b/src/vs/platform/progress/common/progress.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { IAction } from 'vs/base/common/actions'; @@ -15,7 +15,7 @@ export const IProgressService = createDecorator('progressServi */ export interface IProgressService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; withProgress(options: IProgressOptions | IProgressNotificationOptions | IProgressCompositeOptions, task: (progress: IProgress) => Promise, onDidCancel?: () => void): Promise; } @@ -174,5 +174,5 @@ export const IEditorProgressService = createDecorator('e */ export interface IEditorProgressService extends IProgressIndicator { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; } diff --git a/src/vs/platform/quickOpen/common/quickOpen.ts b/src/vs/platform/quickOpen/common/quickOpen.ts index f3b0bcd84d..5a0f053919 100644 --- a/src/vs/platform/quickOpen/common/quickOpen.ts +++ b/src/vs/platform/quickOpen/common/quickOpen.ts @@ -17,7 +17,7 @@ export const IQuickOpenService = createDecorator('quickOpenSe export interface IQuickOpenService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Asks the container to show the quick open control with the optional prefix set. If the optional parameter diff --git a/src/vs/platform/quickinput/common/quickInput.ts b/src/vs/platform/quickinput/common/quickInput.ts index 522a148576..9b5b230596 100644 --- a/src/vs/platform/quickinput/common/quickInput.ts +++ b/src/vs/platform/quickinput/common/quickInput.ts @@ -257,7 +257,7 @@ export type QuickPickInput = T | IQuickPickSeparator; export interface IQuickInputService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Opens the quick input box for selecting items and returns a promise with the user selected item(s) if any. diff --git a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts index 2b55b2f827..8dd2f5ffa4 100644 --- a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts @@ -5,12 +5,18 @@ import { ResolvedAuthority, IRemoteAuthorityResolverService, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { RemoteAuthorities } from 'vs/base/common/network'; +import { URI, UriComponents } from 'vs/base/common/uri'; export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverService { - _serviceBrand: any; + _serviceBrand: undefined; - constructor() { + constructor( + resourceUriProvider: ((uri: URI) => UriComponents) | undefined + ) { + if (resourceUriProvider) { + RemoteAuthorities.setDelegate(resourceUriProvider); + } } resolveAuthority(authority: string): Promise { diff --git a/src/vs/platform/remote/common/remoteAuthorityResolver.ts b/src/vs/platform/remote/common/remoteAuthorityResolver.ts index 80fc027183..86a09affaf 100644 --- a/src/vs/platform/remote/common/remoteAuthorityResolver.ts +++ b/src/vs/platform/remote/common/remoteAuthorityResolver.ts @@ -68,7 +68,7 @@ export class RemoteAuthorityResolverError extends Error { export interface IRemoteAuthorityResolverService { - _serviceBrand: any; + _serviceBrand: undefined; resolveAuthority(authority: string): Promise; diff --git a/src/vs/platform/remote/common/tunnel.ts b/src/vs/platform/remote/common/tunnel.ts index d4f34c9b60..ae1c1207b4 100644 --- a/src/vs/platform/remote/common/tunnel.ts +++ b/src/vs/platform/remote/common/tunnel.ts @@ -15,7 +15,7 @@ export interface RemoteTunnel { } export interface ITunnelService { - _serviceBrand: any; + _serviceBrand: undefined; openTunnel(remotePort: number): Promise | undefined; } diff --git a/src/vs/platform/remote/node/tunnelService.ts b/src/vs/platform/remote/common/tunnelService.ts similarity index 72% rename from src/vs/platform/remote/node/tunnelService.ts rename to src/vs/platform/remote/common/tunnelService.ts index 93200f1258..ba5aa13862 100644 --- a/src/vs/platform/remote/node/tunnelService.ts +++ b/src/vs/platform/remote/common/tunnelService.ts @@ -4,10 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -export class TunnelService implements ITunnelService { - _serviceBrand: any; +export class NoOpTunnelService implements ITunnelService { + _serviceBrand: undefined; public constructor( ) { @@ -17,5 +16,3 @@ export class TunnelService implements ITunnelService { return undefined; } } - -registerSingleton(ITunnelService, TunnelService); diff --git a/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts index 71c5538c75..ab58192100 100644 --- a/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts @@ -18,7 +18,7 @@ class PendingResolveAuthorityRequest { export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverService { - _serviceBrand: any; + _serviceBrand: undefined; private _resolveAuthorityRequests: { [authority: string]: PendingResolveAuthorityRequest; }; diff --git a/src/vs/platform/request/browser/requestService.ts b/src/vs/platform/request/browser/requestService.ts index 5b065d6dd5..7e814466c3 100644 --- a/src/vs/platform/request/browser/requestService.ts +++ b/src/vs/platform/request/browser/requestService.ts @@ -15,7 +15,7 @@ import { request } from 'vs/base/parts/request/browser/request'; */ export class RequestService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @IConfigurationService private readonly configurationService: IConfigurationService, diff --git a/src/vs/platform/request/common/request.ts b/src/vs/platform/request/common/request.ts index be91292939..a00d6b6e12 100644 --- a/src/vs/platform/request/common/request.ts +++ b/src/vs/platform/request/common/request.ts @@ -14,7 +14,7 @@ import { IRequestOptions, IRequestContext } from 'vs/base/parts/request/common/r export const IRequestService = createDecorator('requestService'); export interface IRequestService { - _serviceBrand: any; + _serviceBrand: undefined; request(options: IRequestOptions, token: CancellationToken): Promise; } diff --git a/src/vs/platform/request/common/requestIpc.ts b/src/vs/platform/request/common/requestIpc.ts index 1423b1ee57..7af38615aa 100644 --- a/src/vs/platform/request/common/requestIpc.ts +++ b/src/vs/platform/request/common/requestIpc.ts @@ -40,7 +40,7 @@ export class RequestChannel implements IServerChannel { export class RequestChannelClient { - _serviceBrand: any; + _serviceBrand: undefined; constructor(private readonly channel: IChannel) { } diff --git a/src/vs/platform/request/node/requestService.ts b/src/vs/platform/request/node/requestService.ts index 53b3a372ca..08c1356daf 100644 --- a/src/vs/platform/request/node/requestService.ts +++ b/src/vs/platform/request/node/requestService.ts @@ -36,7 +36,7 @@ export interface NodeRequestOptions extends IRequestOptions { */ export class RequestService extends Disposable implements IRequestService { - _serviceBrand: any; + _serviceBrand: undefined; private proxyUrl?: string; private strictSSL: boolean | undefined; diff --git a/src/vs/platform/sign/browser/signService.ts b/src/vs/platform/sign/browser/signService.ts index 265a81f53b..a356d5a62d 100644 --- a/src/vs/platform/sign/browser/signService.ts +++ b/src/vs/platform/sign/browser/signService.ts @@ -4,11 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { ISignService } from 'vs/platform/sign/common/sign'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class SignService implements ISignService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private readonly _tkn: string | null; diff --git a/src/vs/platform/sign/common/sign.ts b/src/vs/platform/sign/common/sign.ts index 56bfb9e768..37e5ec8f84 100644 --- a/src/vs/platform/sign/common/sign.ts +++ b/src/vs/platform/sign/common/sign.ts @@ -9,7 +9,7 @@ export const SIGN_SERVICE_ID = 'signService'; export const ISignService = createDecorator(SIGN_SERVICE_ID); export interface ISignService { - _serviceBrand: any; + _serviceBrand: undefined; sign(value: string): Promise; } diff --git a/src/vs/platform/sign/node/signService.ts b/src/vs/platform/sign/node/signService.ts index d273fe49b5..addf63a110 100644 --- a/src/vs/platform/sign/node/signService.ts +++ b/src/vs/platform/sign/node/signService.ts @@ -6,7 +6,7 @@ import { ISignService } from 'vs/platform/sign/common/sign'; export class SignService implements ISignService { - _serviceBrand: any; + _serviceBrand: undefined; private vsda(): Promise { return import('vsda'); diff --git a/src/vs/platform/state/common/state.ts b/src/vs/platform/state/common/state.ts index f09be2e7c9..de826c4c2b 100644 --- a/src/vs/platform/state/common/state.ts +++ b/src/vs/platform/state/common/state.ts @@ -8,7 +8,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export const IStateService = createDecorator('stateService'); export interface IStateService { - _serviceBrand: any; + _serviceBrand: undefined; getItem(key: string, defaultValue: T): T; getItem(key: string, defaultValue?: T): T | undefined; diff --git a/src/vs/platform/state/node/stateService.ts b/src/vs/platform/state/node/stateService.ts index 75e2fa8640..66e6261d17 100644 --- a/src/vs/platform/state/node/stateService.ts +++ b/src/vs/platform/state/node/stateService.ts @@ -125,7 +125,7 @@ export class FileStorage { export class StateService implements IStateService { - _serviceBrand: any; + _serviceBrand: undefined; private static STATE_FILE = 'storage.json'; diff --git a/src/vs/platform/statusbar/common/statusbar.ts b/src/vs/platform/statusbar/common/statusbar.ts index e95e4adf62..120d2a8bdc 100644 --- a/src/vs/platform/statusbar/common/statusbar.ts +++ b/src/vs/platform/statusbar/common/statusbar.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable } from 'vs/base/common/lifecycle'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; @@ -59,7 +59,7 @@ export interface IStatusbarEntry { export interface IStatusbarService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; /** * Adds an entry to the statusbar with the given alignment and priority. Use the returned accessor @@ -85,4 +85,4 @@ export interface IStatusbarEntryAccessor extends IDisposable { * Allows to update an existing status bar entry. */ update(properties: IStatusbarEntry): void; -} \ No newline at end of file +} diff --git a/src/vs/platform/storage/browser/storageService.ts b/src/vs/platform/storage/browser/storageService.ts index b35863aeac..bb087f5e5d 100644 --- a/src/vs/platform/storage/browser/storageService.ts +++ b/src/vs/platform/storage/browser/storageService.ts @@ -8,7 +8,6 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IWorkspaceStorageChangeEvent, IStorageService, StorageScope, IWillSaveStateEvent, WillSaveStateReason, logStorage } from 'vs/platform/storage/common/storage'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IFileService, FileChangeType } from 'vs/platform/files/common/files'; import { IStorage, Storage, IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage'; import { URI } from 'vs/base/common/uri'; @@ -19,7 +18,7 @@ import { VSBuffer } from 'vs/base/common/buffer'; export class BrowserStorageService extends Disposable implements IStorageService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private readonly _onDidChangeStorage: Emitter = this._register(new Emitter()); readonly onDidChangeStorage: Event = this._onDidChangeStorage.event; @@ -150,6 +149,10 @@ export class BrowserStorageService extends Disposable implements IStorageService return logStorage(result[0], result[1], this.globalStorageFile.toString(), this.workspaceStorageFile.toString()); } + async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise { + // TODO@ben implement storage migration in web + } + close(): void { // We explicitly do not close our DBs because writing data onBeforeUnload() // can result in unexpected results. Namely, it seems that - even though this diff --git a/src/vs/platform/storage/common/storage.ts b/src/vs/platform/storage/common/storage.ts index 8f2ff78a08..6c74eca416 100644 --- a/src/vs/platform/storage/common/storage.ts +++ b/src/vs/platform/storage/common/storage.ts @@ -3,10 +3,11 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { isUndefinedOrNull } from 'vs/base/common/types'; +import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; export const IStorageService = createDecorator('storageService'); @@ -21,7 +22,7 @@ export interface IWillSaveStateEvent { export interface IStorageService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; /** * Emitted whenever data is updated or deleted. @@ -96,6 +97,11 @@ export interface IStorageService { * Log the contents of the storage to the console. */ logStorage(): void; + + /** + * Migrate the storage contents to another workspace. + */ + migrate(toWorkspace: IWorkspaceInitializationPayload): Promise; } export const enum StorageScope { @@ -118,7 +124,7 @@ export interface IWorkspaceStorageChangeEvent { export class InMemoryStorageService extends Disposable implements IStorageService { - _serviceBrand = null as any; + _serviceBrand: undefined; private readonly _onDidChangeStorage: Emitter = this._register(new Emitter()); readonly onDidChangeStorage: Event = this._onDidChangeStorage.event; @@ -205,6 +211,10 @@ export class InMemoryStorageService extends Disposable implements IStorageServic logStorage(): void { logStorage(this.globalCache, this.workspaceCache, 'inMemory', 'inMemory'); } + + async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise { + // not supported + } } export async function logStorage(global: Map, workspace: Map, globalPath: string, workspacePath: string): Promise { diff --git a/src/vs/platform/storage/node/storageIpc.ts b/src/vs/platform/storage/node/storageIpc.ts index b23c2d507c..064f5a5db8 100644 --- a/src/vs/platform/storage/node/storageIpc.ts +++ b/src/vs/platform/storage/node/storageIpc.ts @@ -147,12 +147,12 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC export class GlobalStorageDatabaseChannelClient extends Disposable implements IStorageDatabase { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _onDidChangeItemsExternal: Emitter = this._register(new Emitter()); readonly onDidChangeItemsExternal: Event = this._onDidChangeItemsExternal.event; - private onDidChangeItemsOnMainListener: IDisposable; + private onDidChangeItemsOnMainListener: IDisposable | undefined; constructor(private channel: IChannel) { super(); diff --git a/src/vs/platform/storage/node/storageMainService.ts b/src/vs/platform/storage/node/storageMainService.ts index 867843c92e..475408aaba 100644 --- a/src/vs/platform/storage/node/storageMainService.ts +++ b/src/vs/platform/storage/node/storageMainService.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; @@ -16,7 +16,7 @@ export const IStorageMainService = createDecorator('storage export interface IStorageMainService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; /** * Emitted whenever data is updated or deleted. @@ -85,7 +85,7 @@ export interface IStorageChangeEvent { export class StorageMainService extends Disposable implements IStorageMainService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private static STORAGE_NAME = 'state.vscdb'; @@ -99,7 +99,7 @@ export class StorageMainService extends Disposable implements IStorageMainServic private storage: IStorage; - private initializePromise: Promise; + private initializePromise: Promise | undefined; constructor( @ILogService private readonly logService: ILogService, diff --git a/src/vs/platform/storage/node/storageService.ts b/src/vs/platform/storage/node/storageService.ts index eb06ea0990..6f35793e1e 100644 --- a/src/vs/platform/storage/node/storageService.ts +++ b/src/vs/platform/storage/node/storageService.ts @@ -15,11 +15,10 @@ import { copy, exists, mkdirp, writeFile } from 'vs/base/node/pfs'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWorkspaceInitializationPayload, isWorkspaceIdentifier, isSingleFolderWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class StorageService extends Disposable implements IStorageService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private static WORKSPACE_STORAGE_NAME = 'state.vscdb'; private static WORKSPACE_META_NAME = 'workspace.json'; diff --git a/src/vs/platform/storage/test/node/storageService.test.ts b/src/vs/platform/storage/test/node/storageService.test.ts index b1d29d6dd9..befc8d53d8 100644 --- a/src/vs/platform/storage/test/node/storageService.test.ts +++ b/src/vs/platform/storage/test/node/storageService.test.ts @@ -12,7 +12,7 @@ import { tmpdir } from 'os'; import { mkdirp, rimraf, RimRafMode } from 'vs/base/node/pfs'; import { NullLogService } from 'vs/platform/log/common/log'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { InMemoryStorageDatabase } from 'vs/base/parts/storage/common/storage'; suite('StorageService', () => { @@ -86,7 +86,7 @@ suite('StorageService', () => { class StorageTestEnvironmentService extends EnvironmentService { constructor(private workspaceStorageFolderPath: string, private _extensionsPath: string) { - super(parseArgs(process.argv), process.execPath); + super(parseArgs(process.argv, OPTIONS), process.execPath); } get workspaceStorageHome(): string { @@ -117,4 +117,4 @@ suite('StorageService', () => { await storage.close(); await rimraf(storageDir, RimRafMode.MOVE); }); -}); \ No newline at end of file +}); diff --git a/src/vs/platform/telemetry/common/telemetry.ts b/src/vs/platform/telemetry/common/telemetry.ts index fed9f3e6e7..7fe82cf8db 100644 --- a/src/vs/platform/telemetry/common/telemetry.ts +++ b/src/vs/platform/telemetry/common/telemetry.ts @@ -12,6 +12,7 @@ export interface ITelemetryInfo { sessionId: string; machineId: string; instanceId: string; + msftInternal?: boolean; } export interface ITelemetryData { @@ -22,7 +23,7 @@ export interface ITelemetryData { export interface ITelemetryService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Sends a telemetry event that has been privacy approved. @@ -43,4 +44,4 @@ export interface ITelemetryService { export const instanceStorageKey = 'telemetry.instanceId'; export const currentSessionDateStorageKey = 'telemetry.currentSessionDate'; export const firstSessionDateStorageKey = 'telemetry.firstSessionDate'; -export const lastSessionDateStorageKey = 'telemetry.lastSessionDate'; \ No newline at end of file +export const lastSessionDateStorageKey = 'telemetry.lastSessionDate'; diff --git a/src/vs/platform/telemetry/common/telemetryService.ts b/src/vs/platform/telemetry/common/telemetryService.ts index 905cf74166..8a2a9ee44c 100644 --- a/src/vs/platform/telemetry/common/telemetryService.ts +++ b/src/vs/platform/telemetry/common/telemetryService.ts @@ -27,7 +27,7 @@ export class TelemetryService implements ITelemetryService { static IDLE_START_EVENT_NAME = 'UserIdleStart'; static IDLE_STOP_EVENT_NAME = 'UserIdleStop'; - _serviceBrand: any; + _serviceBrand: undefined; private _appender: ITelemetryAppender; private _commonProperties: Promise<{ [name: string]: any; }>; @@ -104,8 +104,9 @@ export class TelemetryService implements ITelemetryService { let sessionId = values['sessionID']; let instanceId = values['common.instanceId']; let machineId = values['common.machineId']; + let msftInternal = values['common.msftInternal']; - return { sessionId, instanceId, machineId }; + return { sessionId, instanceId, machineId, msftInternal }; } dispose(): void { diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index 42843b6ab8..ecf75b5803 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -5,7 +5,6 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { IConfigurationService, ConfigurationTarget, ConfigurationTargetToString } from 'vs/platform/configuration/common/configuration'; -import { IKeybindingService, KeybindingSource } from 'vs/platform/keybinding/common/keybinding'; import { ITelemetryService, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { ILogService } from 'vs/platform/log/common/log'; import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings'; @@ -81,118 +80,6 @@ export interface URIDescriptor { path?: string; } -/** - * Only add settings that cannot contain any personal/private information of users (PII). - */ -const configurationValueWhitelist = [ - 'editor.fontFamily', - 'editor.fontWeight', - 'editor.fontSize', - 'editor.lineHeight', - 'editor.letterSpacing', - 'editor.lineNumbers', - 'editor.rulers', - 'editor.wordSeparators', - 'editor.tabSize', - 'editor.indentSize', - 'editor.insertSpaces', - 'editor.detectIndentation', - 'editor.roundedSelection', - 'editor.scrollBeyondLastLine', - 'editor.minimap.enabled', - 'editor.minimap.side', - 'editor.minimap.renderCharacters', - 'editor.minimap.maxColumn', - 'editor.find.seedSearchStringFromSelection', - 'editor.find.autoFindInSelection', - 'editor.wordWrap', - 'editor.wordWrapColumn', - 'editor.wrappingIndent', - 'editor.mouseWheelScrollSensitivity', - 'editor.multiCursorModifier', - 'editor.quickSuggestions', - 'editor.quickSuggestionsDelay', - 'editor.parameterHints.enabled', - 'editor.parameterHints.cycle', - 'editor.autoClosingBrackets', - 'editor.autoClosingQuotes', - 'editor.autoSurround', - 'editor.autoIndent', - 'editor.formatOnType', - 'editor.formatOnPaste', - 'editor.suggestOnTriggerCharacters', - 'editor.acceptSuggestionOnEnter', - 'editor.acceptSuggestionOnCommitCharacter', - 'editor.snippetSuggestions', - 'editor.emptySelectionClipboard', - 'editor.wordBasedSuggestions', - 'editor.suggestSelection', - 'editor.suggestFontSize', - 'editor.suggestLineHeight', - 'editor.tabCompletion', - 'editor.selectionHighlight', - 'editor.occurrencesHighlight', - 'editor.overviewRulerLanes', - 'editor.overviewRulerBorder', - 'editor.cursorBlinking', - 'editor.cursorSmoothCaretAnimation', - 'editor.cursorStyle', - 'editor.mouseWheelZoom', - 'editor.fontLigatures', - 'editor.hideCursorInOverviewRuler', - 'editor.renderWhitespace', - 'editor.renderControlCharacters', - 'editor.renderIndentGuides', - 'editor.renderLineHighlight', - 'editor.codeLens', - 'editor.folding', - 'editor.showFoldingControls', - 'editor.matchBrackets', - 'editor.glyphMargin', - 'editor.useTabStops', - 'editor.trimAutoWhitespace', - 'editor.stablePeek', - 'editor.dragAndDrop', - 'editor.formatOnSave', - 'editor.colorDecorators', - - 'breadcrumbs.enabled', - 'breadcrumbs.filePath', - 'breadcrumbs.symbolPath', - 'breadcrumbs.symbolSortOrder', - 'breadcrumbs.useQuickPick', - 'explorer.openEditors.visible', - 'extensions.autoUpdate', - 'files.associations', - 'files.autoGuessEncoding', - 'files.autoSave', - 'files.autoSaveDelay', - 'files.encoding', - 'files.eol', - 'files.hotExit', - 'files.trimTrailingWhitespace', - 'git.confirmSync', - 'git.enabled', - 'http.proxyStrictSSL', - 'javascript.validate.enable', - 'php.builtInCompletions.enable', - 'php.validate.enable', - 'php.validate.run', - 'terminal.integrated.fontFamily', - 'window.openFilesInNewWindow', - 'window.restoreWindows', - 'window.nativeFullScreen', - 'window.zoomLevel', - 'workbench.editor.enablePreview', - 'workbench.editor.enablePreviewFromQuickOpen', - 'workbench.editor.showTabs', - 'workbench.editor.highlightModifiedTabs', - 'workbench.sideBar.location', - 'workbench.startupEditor', - 'workbench.statusBar.visible', - 'workbench.welcome.enabled', -]; - export function configurationTelemetry(telemetryService: ITelemetryService, configurationService: IConfigurationService): IDisposable { return configurationService.onDidChangeConfiguration(event => { if (event.source !== ConfigurationTarget.DEFAULT) { @@ -208,44 +95,10 @@ export function configurationTelemetry(telemetryService: ITelemetryService, conf configurationSource: ConfigurationTargetToString(event.source), configurationKeys: flattenKeys(event.sourceConfig) }); - type UpdateConfigurationValuesClassification = { - configurationSource: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - configurationValues: { classification: 'CustomerContent', purpose: 'FeatureInsight' }; - }; - type UpdateConfigurationValuesEvent = { - configurationSource: string; - configurationValues: { [key: string]: any }[]; - }; - telemetryService.publicLog2('updateConfigurationValues', { - configurationSource: ConfigurationTargetToString(event.source), - configurationValues: flattenValues(event.sourceConfig, configurationValueWhitelist) - }); } }); } -export function keybindingsTelemetry(telemetryService: ITelemetryService, keybindingService: IKeybindingService): IDisposable { - return keybindingService.onDidUpdateKeybindings(event => { - if (event.source === KeybindingSource.User && event.keybindings) { - type UpdateKeybindingsClassification = { - bindings: { classification: 'CustomerContent', purpose: 'FeatureInsight' }; - }; - type UpdateKeybindingsEvents = { - bindings: { key: string, command: string, when: string | undefined, args: boolean | undefined }[]; - }; - telemetryService.publicLog2('updateKeybindings', { - bindings: event.keybindings.map(binding => ({ - key: binding.key, - command: binding.command, - when: binding.when, - args: binding.args ? true : undefined - })) - }); - } - }); -} - - export interface Properties { [key: string]: string; } @@ -349,18 +202,3 @@ function flatKeys(result: string[], prefix: string, value: { [key: string]: any result.push(prefix); } } - -function flattenValues(value: { [key: string]: any } | undefined, keys: string[]): { [key: string]: any }[] { - if (!value) { - return []; - } - - return keys.reduce((array, key) => { - const v = key.split('.') - .reduce((tmp, k) => tmp && typeof tmp === 'object' ? tmp[k] : undefined, value); - if (typeof v !== 'undefined') { - array.push({ [key]: v }); - } - return array; - }, <{ [key: string]: any }[]>[]); -} diff --git a/src/vs/platform/telemetry/node/commonProperties.ts b/src/vs/platform/telemetry/node/commonProperties.ts index bd89b471fc..28a0f1fdec 100644 --- a/src/vs/platform/telemetry/node/commonProperties.ts +++ b/src/vs/platform/telemetry/node/commonProperties.ts @@ -8,13 +8,11 @@ import * as os from 'os'; import * as uuid from 'vs/base/common/uuid'; import { readFile } from 'vs/base/node/pfs'; -// {{SQL CARBON EDIT}} -import product from 'vs/platform/product/node/product'; -const productObject = product; - -export async function resolveCommonProperties(commit: string | undefined, version: string | undefined, machineId: string | undefined, installSourcePath: string, product?: string): Promise<{ [name: string]: string | undefined; }> { - const result: { [name: string]: string | undefined; } = Object.create(null); - // {{SQL CARBON EDIT}} +import product from 'vs/platform/product/node/product'; // {{SQL CARBON EDIT}} +const productObject = product; // {{SQL CARBON EDIT}} +export async function resolveCommonProperties(commit: string | undefined, version: string | undefined, machineId: string | undefined, msftInternalDomains: string[] | undefined, installSourcePath: string, product?: string): Promise<{ [name: string]: string | boolean | undefined; }> { + const result: { [name: string]: string | boolean | undefined; } = Object.create(null); + // {{SQL CARBON EDIT}} start if (productObject.quality !== 'stable') { // __GDPR__COMMON__ "common.machineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" } result['common.machineId'] = machineId; @@ -31,8 +29,7 @@ export async function resolveCommonProperties(commit: string | undefined, versio result['sessionID'] = ''; // __GDPR__COMMON__ "commitHash" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['commitHash'] = ''; - } - + } // {{SQL CARBON EDIT}} end // __GDPR__COMMON__ "version" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['version'] = version; // __GDPR__COMMON__ "common.platformVersion" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } @@ -47,6 +44,12 @@ export async function resolveCommonProperties(commit: string | undefined, versio result['common.product'] = productObject.nameShort || 'desktop'; // {{SQL CARBON EDIT}} result['common.application.name'] = productObject.nameLong; // {{SQL CARBON EDIT}} + // const msftInternal = verifyMicrosoftInternalDomain(msftInternalDomains || []); {{SQL CARBON EDIT}} remove msft internal + // if (msftInternal) { + // // __GDPR__COMMON__ "common.msftInternal" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + // result['common.msftInternal'] = msftInternal; + // } + // dynamic properties which value differs on each call let seq = 0; const startTime = Date.now(); @@ -84,3 +87,18 @@ export async function resolveCommonProperties(commit: string | undefined, versio return result; } + +function verifyMicrosoftInternalDomain(domainList: string[]): boolean { + if (!process || !process.env || !process.env['USERDNSDOMAIN']) { + return false; + } + + const domain = process.env['USERDNSDOMAIN']!.toLowerCase(); + for (let msftDomain of domainList) { + if (domain === msftDomain) { + return true; + } + } + + return false; +} diff --git a/src/vs/platform/telemetry/node/telemetryNodeUtils.ts b/src/vs/platform/telemetry/node/telemetryNodeUtils.ts deleted file mode 100644 index f3f4c9fb43..0000000000 --- a/src/vs/platform/telemetry/node/telemetryNodeUtils.ts +++ /dev/null @@ -1,20 +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 { URI } from 'vs/base/common/uri'; -import product from 'vs/platform/product/node/product'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; - -export async function addGAParameters(telemetryService: ITelemetryService, environmentService: IEnvironmentService, uri: URI, origin: string, experiment = '1'): Promise { - if (environmentService.isBuilt && !environmentService.isExtensionDevelopment && !environmentService.args['disable-telemetry'] && !!product.enableTelemetry) { - if (uri.scheme === 'https' && uri.authority === 'code.visualstudio.com') { - const info = await telemetryService.getTelemetryInfo(); - - return uri.with({ query: `${uri.query ? uri.query + '&' : ''}utm_source=VsCode&utm_medium=${encodeURIComponent(origin)}&utm_campaign=${encodeURIComponent(info.instanceId)}&utm_content=${encodeURIComponent(experiment)}` }); - } - } - return uri; -} diff --git a/src/vs/platform/telemetry/node/workbenchCommonProperties.ts b/src/vs/platform/telemetry/node/workbenchCommonProperties.ts index ad9a8dedb9..8ebd27a479 100644 --- a/src/vs/platform/telemetry/node/workbenchCommonProperties.ts +++ b/src/vs/platform/telemetry/node/workbenchCommonProperties.ts @@ -10,8 +10,8 @@ import { cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtil import product from 'vs/platform/product/node/product'; // {{ SQL CARBON EDIT }} -export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, installSourcePath: string, remoteAuthority?: string): Promise<{ [name: string]: string | undefined }> { - const result = await resolveCommonProperties(commit, version, machineId, installSourcePath); +export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, msftInternalDomains: string[] | undefined, installSourcePath: string, remoteAuthority?: string): Promise<{ [name: string]: string | boolean | undefined }> { + const result = await resolveCommonProperties(commit, version, machineId, msftInternalDomains, installSourcePath); const instanceId = storageService.get(instanceStorageKey, StorageScope.GLOBAL)!; const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.GLOBAL)!; const lastSessionDate = storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL)!; 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 4acef1165a..64b63f2e0b 100644 --- a/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts @@ -24,7 +24,7 @@ class AppInsightsMock implements ITelemetryClient { } class TestableLogService extends AbstractLogService implements ILogService { - _serviceBrand: any; + _serviceBrand: undefined; public logs: string[] = []; diff --git a/src/vs/platform/telemetry/test/electron-browser/commonProperties.test.ts b/src/vs/platform/telemetry/test/electron-browser/commonProperties.test.ts index dc9e84fe4a..8a564e9e08 100644 --- a/src/vs/platform/telemetry/test/electron-browser/commonProperties.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/commonProperties.test.ts @@ -31,7 +31,7 @@ suite('Telemetry - common properties', function () { test.skip('default', async function () { // {{SQL CARBON EDIT}} skip test await mkdirp(parentDir); fs.writeFileSync(installSource, 'my.install.source'); - const props = await resolveWorkbenchCommonProperties(testStorageService, commit, version, 'someMachineId', installSource); + const props = await resolveWorkbenchCommonProperties(testStorageService, commit, version, 'someMachineId', undefined, installSource); assert.ok('commitHash' in props); assert.ok('sessionID' in props); assert.ok('timestamp' in props); @@ -52,7 +52,7 @@ suite('Telemetry - common properties', function () { assert.ok('common.instanceId' in props, 'instanceId'); assert.ok('common.machineId' in props, 'machineId'); fs.unlinkSync(installSource); - const props_1 = await resolveWorkbenchCommonProperties(testStorageService, commit, version, 'someMachineId', installSource); + const props_1 = await resolveWorkbenchCommonProperties(testStorageService, commit, version, 'someMachineId', undefined, installSource); assert.ok(!('common.source' in props_1)); }); @@ -60,14 +60,14 @@ suite('Telemetry - common properties', function () { testStorageService.store('telemetry.lastSessionDate', new Date().toUTCString(), StorageScope.GLOBAL); - const props = await resolveWorkbenchCommonProperties(testStorageService, commit, version, 'someMachineId', installSource); + const props = await resolveWorkbenchCommonProperties(testStorageService, commit, version, 'someMachineId', undefined, installSource); assert.ok('common.lastSessionDate' in props); // conditional, see below assert.ok('common.isNewSession' in props); assert.equal(props['common.isNewSession'], 0); }); test.skip('values chance on ask', async function () { // {{SQL CARBON EDIT}} skip test - const props = await resolveWorkbenchCommonProperties(testStorageService, commit, version, 'someMachineId', installSource); + const props = await resolveWorkbenchCommonProperties(testStorageService, commit, version, 'someMachineId', undefined, installSource); let value1 = props['common.sequence']; let value2 = props['common.sequence']; assert.ok(value1 !== value2, 'seq'); 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 60202b94c3..3d1a742306 100644 --- a/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts @@ -730,29 +730,29 @@ suite('TelemetryService', () => { let service = new TelemetryService({ appender: testAppender }, { - _serviceBrand: undefined, - getValue() { - return { - enableTelemetry: enableTelemetry - } as any; - }, - updateValue(): Promise { - return null!; - }, - inspect(key: string) { - return { - value: getConfigurationValue(this.getValue(), key), - default: getConfigurationValue(this.getValue(), key), - user: getConfigurationValue(this.getValue(), key), - workspace: null!, - workspaceFolder: null! - }; - }, - keys() { return { default: [], user: [], workspace: [], workspaceFolder: [] }; }, - onDidChangeConfiguration: emitter.event, - reloadConfiguration(): Promise { return null!; }, - getConfigurationData() { return null; } - }); + _serviceBrand: undefined, + getValue() { + return { + enableTelemetry: enableTelemetry + } as any; + }, + updateValue(): Promise { + return null!; + }, + inspect(key: string) { + return { + value: getConfigurationValue(this.getValue(), key), + default: getConfigurationValue(this.getValue(), key), + user: getConfigurationValue(this.getValue(), key), + workspace: null!, + workspaceFolder: null! + }; + }, + keys() { return { default: [], user: [], workspace: [], workspaceFolder: [] }; }, + onDidChangeConfiguration: emitter.event, + reloadConfiguration(): Promise { return null!; }, + getConfigurationData() { return null; } + }); assert.equal(service.isOptedIn, false); diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 8e9f171ef0..69f60e56ad 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -399,6 +399,7 @@ export const overviewRulerFindMatchForeground = registerColor('editorOverviewRul export const overviewRulerSelectionHighlightForeground = registerColor('editorOverviewRuler.selectionHighlightForeground', { dark: '#A0A0A0CC', light: '#A0A0A0CC', hc: '#A0A0A0CC' }, nls.localize('overviewRulerSelectionHighlightForeground', 'Overview ruler marker color for selection highlights. The color must not be opaque so as not to hide underlying decorations.'), true); export const minimapFindMatch = registerColor('minimap.findMatchHighlight', { light: '#d18616', dark: '#d18616', hc: '#AB5A00' }, nls.localize('minimapFindMatchHighlight', 'Minimap marker color for find matches.'), true); +export const minimapSelection = registerColor('minimap.selectionHighlight', { light: '#ADD6FF', dark: '#264F78', hc: '#f3f518' }, nls.localize('minimapSelectionHighlight', 'Minimap marker color for the current editor selection.'), true); // ----- color functions diff --git a/src/vs/platform/theme/common/themeService.ts b/src/vs/platform/theme/common/themeService.ts index 19dbac4bd2..b2e8489377 100644 --- a/src/vs/platform/theme/common/themeService.ts +++ b/src/vs/platform/theme/common/themeService.ts @@ -76,7 +76,7 @@ export interface IThemingParticipant { } export interface IThemeService { - _serviceBrand: any; + _serviceBrand: undefined; getTheme(): ITheme; diff --git a/src/vs/platform/theme/electron-main/themeMainService.ts b/src/vs/platform/theme/electron-main/themeMainService.ts index 0ff6648cac..6acb020255 100644 --- a/src/vs/platform/theme/electron-main/themeMainService.ts +++ b/src/vs/platform/theme/electron-main/themeMainService.ts @@ -18,14 +18,14 @@ const THEME_BG_STORAGE_KEY = 'themeBackground'; export const IThemeMainService = createDecorator('themeMainService'); export interface IThemeMainService { - _serviceBrand: any; + _serviceBrand: undefined; getBackgroundColor(): string; } export class ThemeMainService implements IThemeMainService { - _serviceBrand: any; + _serviceBrand: undefined; constructor(@IStateService private stateService: IStateService) { ipc.on('vscode:changeColorTheme', (e: Event, windowId: number, broadcast: string) => { diff --git a/src/vs/platform/theme/test/common/testThemeService.ts b/src/vs/platform/theme/test/common/testThemeService.ts index 40e87b7b29..45c28936d8 100644 --- a/src/vs/platform/theme/test/common/testThemeService.ts +++ b/src/vs/platform/theme/test/common/testThemeService.ts @@ -33,7 +33,7 @@ export class TestIconTheme implements IIconTheme { export class TestThemeService implements IThemeService { - _serviceBrand: any; + _serviceBrand: undefined; _theme: ITheme; _iconTheme: IIconTheme; _onThemeChange = new Emitter(); diff --git a/src/vs/platform/update/node/update.config.contribution.ts b/src/vs/platform/update/common/update.config.contribution.ts similarity index 96% rename from src/vs/platform/update/node/update.config.contribution.ts rename to src/vs/platform/update/common/update.config.contribution.ts index ebbf16f84c..9759914a6d 100644 --- a/src/vs/platform/update/node/update.config.contribution.ts +++ b/src/vs/platform/update/common/update.config.contribution.ts @@ -6,7 +6,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { localize } from 'vs/nls'; -import { isWindows } from 'vs/base/common/platform'; +import { isWindows, isWeb } from 'vs/base/common/platform'; const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); configurationRegistry.registerConfiguration({ @@ -42,7 +42,7 @@ configurationRegistry.registerConfiguration({ scope: ConfigurationScope.APPLICATION, title: localize('enableWindowsBackgroundUpdatesTitle', "Enable Background Updates on Windows"), description: localize('enableWindowsBackgroundUpdates', "Enable to download and install new VS Code Versions in the background on Windows"), - included: isWindows + included: isWindows && !isWeb }, 'update.showReleaseNotes': { type: 'boolean', diff --git a/src/vs/platform/update/common/update.ts b/src/vs/platform/update/common/update.ts index 7ab91677e0..f5009fd50b 100644 --- a/src/vs/platform/update/common/update.ts +++ b/src/vs/platform/update/common/update.ts @@ -9,8 +9,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export interface IUpdate { version: string; productVersion: string; - date?: Date; - releaseNotes?: string; supportsFastUpdate?: boolean; url?: string; hash?: string; @@ -83,7 +81,7 @@ export interface IAutoUpdater extends Event.NodeEventEmitter { export const IUpdateService = createDecorator('updateService'); export interface IUpdateService { - _serviceBrand: any; + _serviceBrand: undefined; readonly onStateChange: Event; readonly state: State; diff --git a/src/vs/platform/update/electron-browser/updateService.ts b/src/vs/platform/update/electron-browser/updateService.ts index 06502cc228..bc13e47d9c 100644 --- a/src/vs/platform/update/electron-browser/updateService.ts +++ b/src/vs/platform/update/electron-browser/updateService.ts @@ -7,11 +7,10 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { Event, Emitter } from 'vs/base/common/event'; import { IUpdateService, State } from 'vs/platform/update/common/update'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class UpdateService implements IUpdateService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private _onStateChange = new Emitter(); readonly onStateChange: Event = this._onStateChange.event; diff --git a/src/vs/platform/update/electron-main/abstractUpdateService.ts b/src/vs/platform/update/electron-main/abstractUpdateService.ts index ff648d5823..7863278d8b 100644 --- a/src/vs/platform/update/electron-main/abstractUpdateService.ts +++ b/src/vs/platform/update/electron-main/abstractUpdateService.ts @@ -24,7 +24,7 @@ export type UpdateNotAvailableClassification = { export abstract class AbstractUpdateService implements IUpdateService { - _serviceBrand: any; + _serviceBrand: undefined; protected readonly url: string | undefined; diff --git a/src/vs/platform/update/node/updateIpc.ts b/src/vs/platform/update/electron-main/updateIpc.ts similarity index 100% rename from src/vs/platform/update/node/updateIpc.ts rename to src/vs/platform/update/electron-main/updateIpc.ts diff --git a/src/vs/platform/update/electron-main/updateService.darwin.ts b/src/vs/platform/update/electron-main/updateService.darwin.ts index aae7fed84c..539f9d79c1 100644 --- a/src/vs/platform/update/electron-main/updateService.darwin.ts +++ b/src/vs/platform/update/electron-main/updateService.darwin.ts @@ -18,7 +18,7 @@ import { IRequestService } from 'vs/platform/request/common/request'; export class DarwinUpdateService extends AbstractUpdateService { - _serviceBrand: any; + _serviceBrand: undefined; private disposables: IDisposable[] = []; diff --git a/src/vs/platform/update/electron-main/updateService.linux.ts b/src/vs/platform/update/electron-main/updateService.linux.ts index 8efcbd3efb..d895054ad1 100644 --- a/src/vs/platform/update/electron-main/updateService.linux.ts +++ b/src/vs/platform/update/electron-main/updateService.linux.ts @@ -17,7 +17,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; export class LinuxUpdateService extends AbstractUpdateService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @ILifecycleService lifecycleService: ILifecycleService, diff --git a/src/vs/platform/update/electron-main/updateService.snap.ts b/src/vs/platform/update/electron-main/updateService.snap.ts index 6a0c359a09..e5449de382 100644 --- a/src/vs/platform/update/electron-main/updateService.snap.ts +++ b/src/vs/platform/update/electron-main/updateService.snap.ts @@ -17,7 +17,7 @@ import { UpdateNotAvailableClassification } from 'vs/platform/update/electron-ma abstract class AbstractUpdateService2 implements IUpdateService { - _serviceBrand: any; + _serviceBrand: undefined; private _state: State = State.Uninitialized; @@ -134,7 +134,7 @@ abstract class AbstractUpdateService2 implements IUpdateService { export class SnapUpdateService extends AbstractUpdateService2 { - _serviceBrand: any; + _serviceBrand: undefined; constructor( private snap: string, diff --git a/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts index 2dcabb8387..4898949819 100644 --- a/src/vs/platform/update/electron-main/updateService.win32.ts +++ b/src/vs/platform/update/electron-main/updateService.win32.ts @@ -49,7 +49,7 @@ function getUpdateType(): UpdateType { export class Win32UpdateService extends AbstractUpdateService { - _serviceBrand: any; + _serviceBrand: undefined; private availableUpdate: IAvailableUpdate | undefined; diff --git a/src/vs/platform/url/common/url.ts b/src/vs/platform/url/common/url.ts index 4a560ee5a0..3fc2a53c13 100644 --- a/src/vs/platform/url/common/url.ts +++ b/src/vs/platform/url/common/url.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { URI, UriComponents } from 'vs/base/common/uri'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable } from 'vs/base/common/lifecycle'; export const IURLService = createDecorator('urlService'); @@ -15,7 +15,7 @@ export interface IURLHandler { export interface IURLService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; /** * Create a URL that can be called to trigger IURLhandlers. diff --git a/src/vs/platform/url/node/urlIpc.ts b/src/vs/platform/url/common/urlIpc.ts similarity index 64% rename from src/vs/platform/url/node/urlIpc.ts rename to src/vs/platform/url/common/urlIpc.ts index 94ed13bec2..0822f1053a 100644 --- a/src/vs/platform/url/node/urlIpc.ts +++ b/src/vs/platform/url/common/urlIpc.ts @@ -3,11 +3,13 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; +import { IChannel, IServerChannel, IClientRouter, IConnectionHub, Client } from 'vs/base/parts/ipc/common/ipc'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { first } from 'vs/base/common/arrays'; export class URLServiceChannel implements IServerChannel { @@ -28,7 +30,7 @@ export class URLServiceChannel implements IServerChannel { export class URLServiceChannelClient implements IURLService { - _serviceBrand: any; + _serviceBrand: undefined; constructor(private channel: IChannel) { } @@ -70,3 +72,37 @@ export class URLHandlerChannelClient implements IURLHandler { return this.channel.call('handleURL', uri.toJSON()); } } + +export class URLHandlerRouter implements IClientRouter { + + constructor(private next: IClientRouter) { } + + async routeCall(hub: IConnectionHub, command: string, arg?: any, cancellationToken?: CancellationToken): Promise> { + if (command !== 'handleURL') { + throw new Error(`Call not found: ${command}`); + } + + if (arg) { + const uri = URI.revive(arg); + + if (uri && uri.query) { + const match = /\bwindowId=([^&]+)/.exec(uri.query); + + if (match) { + const windowId = match[1]; + const connection = first(hub.connections, c => c.ctx === windowId); + + if (connection) { + return connection; + } + } + } + } + + return this.next.routeCall(hub, command, arg, cancellationToken); + } + + routeEvent(_: IConnectionHub, event: string): Promise> { + throw new Error(`Event not found: ${event}`); + } +} diff --git a/src/vs/platform/url/common/urlService.ts b/src/vs/platform/url/common/urlService.ts index db77ad2e40..bb4ba2113d 100644 --- a/src/vs/platform/url/common/urlService.ts +++ b/src/vs/platform/url/common/urlService.ts @@ -8,11 +8,10 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { values } from 'vs/base/common/map'; import { first } from 'vs/base/common/async'; import { toDisposable, IDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export abstract class AbstractURLService extends Disposable implements IURLService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private handlers = new Set(); diff --git a/src/vs/platform/url/node/urlService.ts b/src/vs/platform/url/node/urlService.ts index c9a5b41ac2..25928b6240 100644 --- a/src/vs/platform/url/node/urlService.ts +++ b/src/vs/platform/url/node/urlService.ts @@ -10,7 +10,11 @@ import { AbstractURLService } from 'vs/platform/url/common/urlService'; export class URLService extends AbstractURLService { create(options?: Partial): URI { - const { authority, path, query, fragment } = options ? options : { authority: undefined, path: undefined, query: undefined, fragment: undefined }; + let { authority, path, query, fragment } = options ? options : { authority: undefined, path: undefined, query: undefined, fragment: undefined }; + + if (authority && path && path.indexOf('/') !== 0) { + path = `/${path}`; // URI validation requires a path if there is an authority + } return URI.from({ scheme: product.urlProtocol, authority, path, query, fragment }); } diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index cf96c54ae8..9f91c8760c 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -94,7 +94,7 @@ export interface IDevToolsOptions { export interface IWindowsService { - _serviceBrand: any; + _serviceBrand: undefined; readonly onWindowOpen: Event; readonly onWindowFocus: Event; @@ -221,7 +221,7 @@ export function isFileToOpen(uriToOpen: IURIToOpen): uriToOpen is IFileToOpen { export interface IWindowService { - _serviceBrand: any; + _serviceBrand: undefined; readonly onDidChangeFocus: Event; readonly onDidChangeMaximize: Event; diff --git a/src/vs/platform/windows/electron-browser/windowsService.ts b/src/vs/platform/windows/electron-browser/windowsService.ts index 1a910cd8c9..39d7cf5cb8 100644 --- a/src/vs/platform/windows/electron-browser/windowsService.ts +++ b/src/vs/platform/windows/electron-browser/windowsService.ts @@ -13,11 +13,10 @@ import { URI } from 'vs/base/common/uri'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; import { IProcessEnvironment } from 'vs/base/common/platform'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class WindowsService implements IWindowsService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private channel: IChannel; diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 9aa3d63faa..c8a46a9a31 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -84,7 +84,7 @@ export interface IWindowsCountChangedEvent { } export interface IWindowsMainService { - _serviceBrand: any; + _serviceBrand: undefined; // events readonly onWindowReady: Event; @@ -96,7 +96,7 @@ export interface IWindowsMainService { enterWorkspace(win: ICodeWindow, path: URI): Promise; closeWorkspace(win: ICodeWindow): void; open(openConfig: IOpenConfiguration): ICodeWindow[]; - openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string | string[], openConfig: IOpenConfiguration): void; + openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): void; pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise; pickFolderAndOpen(options: INativeOpenDialogOptions): Promise; pickFileAndOpen(options: INativeOpenDialogOptions): Promise; @@ -140,4 +140,4 @@ export interface IOpenConfiguration { export interface ISharedProcess { whenReady(): Promise; toggle(): void; -} \ No newline at end of file +} diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index e573543f0c..709c9af83f 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -23,11 +23,10 @@ import { Schemas } from 'vs/base/common/network'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { isMacintosh, isLinux, IProcessEnvironment } from 'vs/base/common/platform'; import { ILogService } from 'vs/platform/log/common/log'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class WindowsService extends Disposable implements IWindowsService, IURLHandler { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private readonly disposables = this._register(new DisposableStore()); @@ -310,8 +309,9 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH async openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise { this.logService.trace('windowsService#openExtensionDevelopmentHostWindow ' + JSON.stringify(args)); - if (args.extensionDevelopmentPath) { - this.windowsMainService.openExtensionDevelopmentHostWindow(args.extensionDevelopmentPath, { + const extDevPaths = args.extensionDevelopmentPath; + if (extDevPaths) { + this.windowsMainService.openExtensionDevelopmentHostWindow(extDevPaths, { context: OpenContext.API, cli: args, userEnv: Object.keys(env).length > 0 ? env : undefined @@ -323,9 +323,14 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH this.logService.trace('windowsService#getWindows'); const windows = this.windowsMainService.getWindows(); - const result = windows.map(w => ({ id: w.id, workspace: w.openedWorkspace, folderUri: w.openedFolderUri, title: w.win.getTitle(), filename: w.getRepresentedFilename() })); - return result; + return windows.map(window => ({ + id: window.id, + workspace: window.openedWorkspace, + folderUri: window.openedFolderUri, + title: window.win.getTitle(), + filename: window.getRepresentedFilename() + })); } async getWindowCount(): Promise { diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index c5459ee69a..f558e667d0 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -25,7 +25,7 @@ export interface IWorkspaceFoldersChangeEvent { } export interface IWorkspaceContextService { - _serviceBrand: any; + _serviceBrand: undefined; /** * An event which fires on workbench state changes. diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index a7898ab9f0..353de67924 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -96,7 +96,7 @@ export interface IUntitledWorkspaceInfo { } export interface IWorkspacesMainService extends IWorkspacesService { - _serviceBrand: any; + _serviceBrand: undefined; onUntitledWorkspaceDeleted: Event; @@ -112,7 +112,7 @@ export interface IWorkspacesMainService extends IWorkspacesService { } export interface IWorkspacesService { - _serviceBrand: any; + _serviceBrand: undefined; createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise; diff --git a/src/vs/platform/workspaces/electron-browser/workspacesService.ts b/src/vs/platform/workspaces/electron-browser/workspacesService.ts index 3f6d27265f..6107be9d05 100644 --- a/src/vs/platform/workspaces/electron-browser/workspacesService.ts +++ b/src/vs/platform/workspaces/electron-browser/workspacesService.ts @@ -6,12 +6,11 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IWorkspacesService, IWorkspaceIdentifier, IWorkspaceFolderCreationData, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; export class WorkspacesService implements IWorkspacesService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; private channel: IChannel; diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index 04002299fc..5ec16e4950 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -26,7 +26,7 @@ export interface IStoredWorkspace { export class WorkspacesMainService extends Disposable implements IWorkspacesMainService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly untitledWorkspacesHome: URI; // local URI that contains all untitled workspaces diff --git a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts index 7c52f5f9e5..3981d935ca 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts @@ -9,7 +9,7 @@ import * as os from 'os'; import * as path from 'vs/base/common/path'; import * as pfs from 'vs/base/node/pfs'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { WorkspacesMainService, IStoredWorkspace } from 'vs/platform/workspaces/electron-main/workspacesMainService'; import { WORKSPACE_EXTENSION, IWorkspaceIdentifier, IRawFileWorkspaceFolder, IWorkspaceFolderCreationData, IRawUriWorkspaceFolder, rewriteWorkspaceFileForNewLocation } from 'vs/platform/workspaces/common/workspaces'; import { NullLogService } from 'vs/platform/log/common/log'; @@ -47,7 +47,7 @@ suite('WorkspacesMainService', () => { return service.createUntitledWorkspaceSync(folders.map((folder, index) => ({ uri: URI.file(folder), name: names ? names[index] : undefined } as IWorkspaceFolderCreationData))); } - const environmentService = new TestEnvironmentService(parseArgs(process.argv), process.execPath); + const environmentService = new TestEnvironmentService(parseArgs(process.argv, OPTIONS), process.execPath); const logService = new NullLogService(); let service: TestWorkspacesMainService; diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 374b44d3bf..d7e7145185 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2532,6 +2532,18 @@ declare module 'vscode' { TypeParameter = 25 } + + /** + * Symbol tags are extra annotations that tweak the rendering of a symbol. + */ + export enum SymbolTag { + + /** + * Render a symbol as obsolete, usually using a strike-out. + */ + Deprecated = 1 + } + /** * Represents information about programming constructs like variables, classes, * interfaces etc. @@ -2553,6 +2565,11 @@ declare module 'vscode' { */ kind: SymbolKind; + /** + * Tags for this symbol. + */ + tags?: ReadonlyArray; + /** * The location of this symbol. */ @@ -2604,6 +2621,11 @@ declare module 'vscode' { */ kind: SymbolKind; + /** + * Tags for this symbol. + */ + tags?: ReadonlyArray; + /** * The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. */ @@ -3285,6 +3307,17 @@ declare module 'vscode' { TypeParameter = 24 } + /** + * Completion item tags are extra annotations that tweak the rendering of a completion + * item. + */ + export enum CompletionItemTag { + /** + * Render a completion as obsolete, usually using a strike-out. + */ + Deprecated = 1 + } + /** * A completion item represents a text snippet that is proposed to complete text that is being typed. * @@ -3315,6 +3348,11 @@ declare module 'vscode' { */ kind?: CompletionItemKind; + /** + * Tags for this completion item. + */ + tags?: ReadonlyArray; + /** * A human-readable string with additional information * about this item, like type or symbol information. @@ -5912,22 +5950,27 @@ declare module 'vscode' { /** * Fired when the webview content posts a message. + * + * Webview content can post strings or json serilizable objects back to a VS Code extension. They cannot + * post `Blob`, `File`, `ImageData` and other DOM specific objects since the extension that receives the + * message does not run in a browser environment. */ readonly onDidReceiveMessage: Event; /** * Post a message to the webview content. * - * Messages are only delivered if the webview is visible. + * Messages are only delivered if the webview is live (either visible or in the + * background with `retainContextWhenHidden`). * - * @param message Body of the message. + * @param message Body of the message. This must be a string or other json serilizable object. */ postMessage(message: any): Thenable; /** * Convert a uri for the local file system to one that can be used inside webviews. * - * Webviews cannot directly load resoruces from the workspace or local file system using `file:` uris. The + * Webviews cannot directly load resources from the workspace or local file system using `file:` uris. The * `asWebviewUri` function takes a local `file:` uri and converts it into a uri that can be used inside of * a webview to load the same resource: * @@ -6792,26 +6835,35 @@ declare module 'vscode' { export function createStatusBarItem(alignment?: StatusBarAlignment, priority?: number): StatusBarItem; /** - * Creates a [Terminal](#Terminal). The cwd of the terminal will be the workspace directory - * if it exists, regardless of whether an explicit customStartPath setting exists. + * Creates a [Terminal](#Terminal) with a backing shell process. The cwd of the terminal will be the workspace + * directory if it exists. * * @param name Optional human-readable string which will be used to represent the terminal in the UI. * @param shellPath Optional path to a custom shell executable to be used in the terminal. * @param shellArgs Optional args for the custom shell executable. A string can be used on Windows only which - * allows specifying shell args in [command-line format](https://msdn.microsoft.com/en-au/08dfcab2-eb6e-49a4-80eb-87d4076c98c6). + * allows specifying shell args in + * [command-line format](https://msdn.microsoft.com/en-au/08dfcab2-eb6e-49a4-80eb-87d4076c98c6). * @return A new Terminal. */ export function createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): Terminal; /** - * Creates a [Terminal](#Terminal). The cwd of the terminal will be the workspace directory - * if it exists, regardless of whether an explicit customStartPath setting exists. + * Creates a [Terminal](#Terminal) with a backing shell process. * * @param options A TerminalOptions object describing the characteristics of the new terminal. * @return A new Terminal. */ export function createTerminal(options: TerminalOptions): Terminal; + /** + * Creates a [Terminal](#Terminal) where an extension controls its input and output. + * + * @param options An [ExtensionTerminalOptions](#ExtensionTerminalOptions) object describing + * the characteristics of the new terminal. + * @return A new Terminal. + */ + export function createTerminal(options: ExtensionTerminalOptions): Terminal; + /** * Register a [TreeDataProvider](#TreeDataProvider) for the view contributed using the extension point `views`. * This will allow you to contribute data to the [TreeView](#TreeView) and update if the data changes. @@ -6886,7 +6938,7 @@ declare module 'vscode' { /** * Whether the tree supports multi-select. When the tree supports multi-select and a command is executed from the tree, * the first argument to the command is the tree item that the command was executed on and the second argument is an - * array containing the other selected tree items. + * array containing all selected tree items. */ canSelectMany?: boolean; } @@ -7165,6 +7217,169 @@ declare module 'vscode' { hideFromUser?: boolean; } + /** + * Value-object describing what options a virtual process terminal should use. + */ + export interface ExtensionTerminalOptions { + /** + * A human-readable string which will be used to represent the terminal in the UI. + */ + name: string; + + /** + * An implementation of [Pseudoterminal](#Pseudoterminal) that allows an extension to + * control a terminal. + */ + pty: Pseudoterminal; + } + + /** + * Defines the interface of a terminal pty, enabling extensions to control a terminal. + */ + 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_ + * (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 pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * open: () => writeEmitter.fire('\x1b[31mHello world\x1b[0m'), + * close: () => {} + * }; + * vscode.window.createTerminal({ name: 'My terminal', pty }); + * ``` + * + * **Example:** Move the cursor to the 10th row and 20th column and write an asterisk + * ```typescript + * writeEmitter.fire('\x1b[10;20H*'); + * ``` + */ + onDidWrite: Event; + + /** + * 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 (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 pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * onDidOverrideDimensions: dimensionsEmitter.event, + * open: () => { + * dimensionsEmitter.fire({ + * columns: 20, + * rows: 10 + * }); + * }, + * close: () => {} + * }; + * vscode.window.createTerminal({ name: 'My terminal', pty }); + * ``` + */ + onDidOverrideDimensions?: Event; + + /** + * An event that when fired will signal that the pty is closed and dispose of the terminal. + * + * A number can be used to provide an exit code for the terminal. Exit codes must be + * positive and a non-zero exit codes signals failure which shows a notification for a + * regular terminal and allows dependent tasks to proceed when used with the + * `CustomExecution2` API. + * + * **Example:** Exit the terminal when "y" is pressed, otherwise show a notification. + * ```typescript + * const writeEmitter = new vscode.EventEmitter(); + * const closeEmitter = new vscode.EventEmitter(); + * const pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * onDidClose: closeEmitter.event, + * open: () => writeEmitter.fire('Press y to exit successfully'), + * close: () => {}, + * handleInput: data => { + * if (data !== 'y') { + * vscode.window.showInformationMessage('Something went wrong'); + * } + * closeEmitter.fire(); + * } + * }; + * vscode.window.createTerminal({ name: 'Exit example', pty }); + */ + onDidClose?: Event; + + /** + * Implement to handle when the pty is open and 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. + */ + 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 pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * open: () => {}, + * close: () => {}, + * handleInput: data => writeEmitter.fire(data === '\r' ? '\r\n' : data) + * }; + * vscode.window.createTerminal({ name: 'Local echo', pty }); + * ``` + */ + handleInput?(data: string): void; + + /** + * Implement to handle when the number of rows and columns that fit into the terminal panel + * changes, for example when font size changes or when the panel is resized. The initial + * state of a terminal's dimensions should be treated as `undefined` until this is triggered + * as the size of a terminal isn't know until it shows up in the user interface. + * + * When dimensions are overridden by + * [onDidOverrideDimensions](#Pseudoterminal.onDidOverrideDimensions), `setDimensions` will + * continue to be called with the regular panel dimensions, allowing the extension continue + * to react dimension changes. + * + * @param dimensions The new dimensions. + */ + setDimensions?(dimensions: TerminalDimensions): void; + } + + /** + * Represents the dimensions of a terminal. + */ + export interface TerminalDimensions { + /** + * The number of columns in the terminal. + */ + readonly columns: number; + + /** + * The number of rows in the terminal. + */ + readonly rows: number; + } + /** * A location in the editor at which progress information can be shown. It depends on the * location how progress is visually represented. @@ -7844,7 +8059,8 @@ declare module 'vscode' { * * `file`-scheme: Open a file on disk, will be rejected if the file does not exist or cannot be loaded. * * `untitled`-scheme: A new file that should be saved on disk, e.g. `untitled:c:\frodo\new.js`. The language * will be derived from the file name. - * * For all other schemes the registered text document content [providers](#TextDocumentContentProvider) are consulted. + * * For all other schemes contributed [text document content providers](#TextDocumentContentProvider) and + * [file system providers](#FileSystemProvider) are consulted. * * *Note* that the lifecycle of the returned document is owned by the editor and not by the extension. That means an * [`onDidClose`](#workspace.onDidCloseTextDocument)-event can occur at any time after opening it. @@ -8090,8 +8306,7 @@ declare module 'vscode' { export const onDidChangeDiagnostics: Event; /** - * Get all diagnostics for a given resource. *Note* that this includes diagnostics from - * all extensions but *not yet* from the task framework. + * Get all diagnostics for a given resource. * * @param resource A resource * @returns An array of [diagnostics](#Diagnostic) objects or an empty array. @@ -8099,8 +8314,7 @@ declare module 'vscode' { export function getDiagnostics(resource: Uri): Diagnostic[]; /** - * Get all diagnostics. *Note* that this includes diagnostics from - * all extensions but *not yet* from the task framework. + * Get all diagnostics. * * @returns An array of uri-diagnostics tuples or an empty array. */ @@ -8689,9 +8903,10 @@ declare module 'vscode' { readonly type: string; /** - * The debug session's name from the [debug configuration](#DebugConfiguration). + * The debug session's name is initially taken from the [debug configuration](#DebugConfiguration). + * Any changes will be properly reflected in the UI. */ - readonly name: string; + name: string; /** * The workspace folder of this session or `undefined` for a folderless setup. diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 78c6973fe0..59ea920f5f 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -16,62 +16,80 @@ declare module 'vscode' { - //#region Joh - ExecutionContext - // THIS is a deprecated proposal - export enum ExtensionExecutionContext { - Local = 1, - Remote = 2 - } - export interface ExtensionContext { - executionContext: ExtensionExecutionContext; - } - //#endregion - //#region Joh - call hierarchy - export enum CallHierarchyDirection { - CallsFrom = 1, - CallsTo = 2, - } - export class CallHierarchyItem { - kind: SymbolKind; + /** + * The name of this item. + */ name: string; + + /** + * The kind of this item. + */ + kind: SymbolKind; + + /** + * Tags for this item. + */ + tags?: ReadonlyArray; + + /** + * More detail for this item, e.g. the signature of a function. + */ detail?: string; + + /** + * The resource identifier of this item. + */ uri: Uri; + + /** + * The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. + */ range: Range; + + /** + * The range that should be selected and reveal when this symbol is being picked, e.g. the name of a function. + * Must be contained by the [`range`](#CallHierarchyItem.range). + */ selectionRange: Range; constructor(kind: SymbolKind, name: string, detail: string, uri: Uri, range: Range, selectionRange: Range); } + export class CallHierarchyIncomingCall { + source: CallHierarchyItem; + sourceRanges: Range[]; + constructor(item: CallHierarchyItem, sourceRanges: Range[]); + } + + export class CallHierarchyOutgoingCall { + sourceRanges: Range[]; + target: CallHierarchyItem; + constructor(item: CallHierarchyItem, sourceRanges: Range[]); + } + export interface CallHierarchyItemProvider { /** - * Given a document and position compute a call hierarchy item. This is justed as - * anchor for call hierarchy and then `resolveCallHierarchyItem` is being called. + * Provide a list of callers for the provided item, e.g. all function calling a function. */ - provideCallHierarchyItem( - document: TextDocument, - position: Position, - token: CancellationToken - ): ProviderResult; + provideCallHierarchyIncomingCalls(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; /** - * Resolve a call hierarchy item, e.g. compute all calls from or to a function. - * The result is an array of item/location-tuples. The location in the returned tuples - * is always relative to the "caller" with the caller either being the provided item or - * the returned item. - * - * @param item A call hierarchy item previously returned from `provideCallHierarchyItem` or `resolveCallHierarchyItem` - * @param direction Resolve calls from a function or calls to a function - * @param token A cancellation token + * Provide a list of calls for the provided item, e.g. all functions call from a function. */ - resolveCallHierarchyItem( - item: CallHierarchyItem, - direction: CallHierarchyDirection, - token: CancellationToken - ): ProviderResult<[CallHierarchyItem, Location[]][]>; + provideCallHierarchyOutgoingCalls(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + + // todo@joh this could return as 'prepareCallHierarchy' (similar to the RenameProvider#prepareRename) + // + // /** + // * + // * Given a document and position compute a call hierarchy item. This is justed as + // * anchor for call hierarchy and then `resolveCallHierarchyItem` is being called. + // */ + // resolveCallHierarchyItem(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; } export namespace languages { @@ -567,25 +585,17 @@ declare module 'vscode' { //#region Joh: decorations - //todo@joh -> make class - export interface DecorationData { + export class Decoration { letter?: string; title?: string; color?: ThemeColor; priority?: number; bubble?: boolean; - source?: string; // hacky... we should remove it and use equality under the hood - } - - export interface SourceControlResourceDecorations { - source?: string; - letter?: string; - color?: ThemeColor; } export interface DecorationProvider { onDidChangeDecorations: Event; - provideDecoration(uri: Uri, token: CancellationToken): ProviderResult; + provideDecoration(uri: Uri, token: CancellationToken): ProviderResult; } export namespace window { @@ -768,193 +778,6 @@ declare module 'vscode' { * created. */ readonly dimensions: TerminalDimensions | undefined; - - /** - * Fires when the terminal's pty slave pseudo-device is written to. In other words, this - * provides access to the raw data stream from the process running within the terminal, - * including VT sequences. - * - * @deprecated Use [window.onDidWriteTerminalData](#onDidWriteTerminalData). - */ - readonly onDidWriteData: Event; - } - - /** - * Represents the dimensions of a terminal. - */ - export interface TerminalDimensions { - /** - * The number of columns in the terminal. - */ - readonly columns: number; - - /** - * The number of rows in the terminal. - */ - readonly rows: number; - } - - //#endregion - - //#region Extension terminals - - export namespace window { - /** - * Creates a [Terminal](#Terminal) where an extension controls the terminal. - * - * @param options An [ExtensionTerminalOptions](#ExtensionTerminalOptions) object describing - * the characteristics of the new terminal. - * @return A new Terminal. - */ - export function createTerminal(options: ExtensionTerminalOptions): Terminal; - } - - /** - * Value-object describing what options a virtual process terminal should use. - */ - export interface ExtensionTerminalOptions { - /** - * A human-readable string which will be used to represent the terminal in the UI. - */ - name: string; - - /** - * An implementation of [Pseudoterminal](#Pseudoterminal) that allows an extension to - * control a terminal. - */ - pty: Pseudoterminal; - } - - /** - * Defines the interface of a terminal pty, enabling extensions to control a terminal. - */ - 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_ - * (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 pty: vscode.Pseudoterminal = { - * onDidWrite: writeEmitter.event, - * open: () => writeEmitter.fire('\x1b[31mHello world\x1b[0m'), - * close: () => {} - * }; - * vscode.window.createTerminal({ name: 'My terminal', pty }); - * ``` - * - * **Example:** Move the cursor to the 10th row and 20th column and write an asterisk - * ```typescript - * writeEmitter.fire('\x1b[10;20H*'); - * ``` - */ - onDidWrite: Event; - - /** - * 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 (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 pty: vscode.Pseudoterminal = { - * onDidWrite: writeEmitter.event, - * onDidOverrideDimensions: dimensionsEmitter.event, - * open: () => { - * dimensionsEmitter.fire({ - * columns: 20, - * rows: 10 - * }); - * }, - * close: () => {} - * }; - * vscode.window.createTerminal({ name: 'My terminal', pty }); - * ``` - */ - onDidOverrideDimensions?: Event; - - /** - * An event that when fired will signal that the pty is closed and dispose of the terminal. - * - * A number can be used to provide an exit code for the terminal. Exit codes must be - * positive and a non-zero exit codes signals failure which shows a notification for a - * regular terminal and allows dependent tasks to proceed when used with the - * `CustomExecution2` API. - * - * **Example:** Exit the terminal when "y" is pressed, otherwise show a notification. - * ```typescript - * const writeEmitter = new vscode.EventEmitter(); - * const closeEmitter = new vscode.EventEmitter(); - * const pty: vscode.Pseudoterminal = { - * onDidWrite: writeEmitter.event, - * onDidClose: closeEmitter.event, - * open: () => writeEmitter.fire('Press y to exit successfully'), - * close: () => {} - * handleInput: data => { - * if (data !== 'y') { - * vscode.window.showInformationMessage('Something went wrong'); - * } - * closeEmitter.fire(); - * } - * }; - * vscode.window.createTerminal({ name: 'Exit example', pty }); - */ - onDidClose?: Event; - - /** - * Implement to handle when the pty is open and 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. - */ - 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 pty: vscode.Pseudoterminal = { - * onDidWrite: writeEmitter.event, - * open: () => {}, - * close: () => {}, - * handleInput: data => writeEmitter.fire(data === '\r' ? '\r\n' : data) - * }; - * vscode.window.createTerminal({ name: 'Local echo', pty }); - * ``` - */ - handleInput?(data: string): void; - - /** - * Implement to handle when the number of rows and columns that fit into the terminal panel - * changes, for example when font size changes or when the panel is resized. The initial - * state of a terminal's dimensions should be treated as `undefined` until this is triggered - * as the size of a terminal isn't know until it shows up in the user interface. - * - * When dimensions are overridden by - * [onDidOverrideDimensions](#Pseudoterminal.onDidOverrideDimensions), `setDimensions` will - * continue to be called with the regular panel dimensions, allowing the extension continue - * to react dimension changes. - * - * @param dimensions The new dimensions. - */ - setDimensions?(dimensions: TerminalDimensions): void; } //#endregion @@ -1003,6 +826,10 @@ declare module 'vscode' { */ message?: string; + /** + * The name of the tree view. It is set from the extension package.json and can be changed later. + */ + title?: string; } /** @@ -1046,14 +873,14 @@ declare module 'vscode' { * @param process The [Pseudoterminal](#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: () => Thenable); /** * 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: () => Thenable; } /** @@ -1138,40 +965,6 @@ declare module 'vscode' { //#endregion - //#region Joh - CompletionItemTag, https://github.com/microsoft/vscode/issues/23927 - - export enum SymbolTag { - Deprecated = 1 - } - - export interface SymbolInformation { - /** - * - */ - tags?: ReadonlyArray; - } - - export interface DocumentSymbol { - /** - * - */ - tags?: ReadonlyArray; - } - - export enum CompletionItemTag { - Deprecated = 1 - } - - export interface CompletionItem { - - /** - * - */ - tags?: ReadonlyArray; - } - - //#endregion - // #region Ben - extension auth flow (desktop+web) export interface AppUriOptions { @@ -1217,4 +1010,37 @@ declare module 'vscode' { } //#endregion + + //#region Custom editors, mjbvz + + export enum WebviewEditorState { + Readonly = 1, + Unchanged = 2, + Dirty = 3, + } + + export interface WebviewEditor extends WebviewPanel { + state: WebviewEditorState; + } + + export interface WebviewEditorProvider { + /** + * Fills out a `WebviewEditor` for a given resource. + * + * The provider should take ownership of passed in `editor`. + */ + resolveWebviewEditor( + resource: Uri, + editor: WebviewEditor + ): Thenable; + } + + namespace window { + export function registerWebviewEditorProvider( + viewType: string, + provider: WebviewEditorProvider, + ): Disposable; + } + + //#endregion } diff --git a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts index 4306632596..13fadfb87a 100644 --- a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts +++ b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts @@ -92,9 +92,9 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape { enableFindWidget: false, extension: { id: extensionId, location: URI.revive(extensionLocation) } }, { - allowScripts: options.enableScripts, - localResourceRoots: options.localResourceRoots ? options.localResourceRoots.map(uri => URI.revive(uri)) : undefined - }); + allowScripts: options.enableScripts, + localResourceRoots: options.localResourceRoots ? options.localResourceRoots.map(uri => URI.revive(uri)) : undefined + }); const webviewZone = new EditorWebviewZone(editor, line, height, webview); diff --git a/src/vs/workbench/api/browser/mainThreadCommands.ts b/src/vs/workbench/api/browser/mainThreadCommands.ts index e6e86b909f..22fca9bcaf 100644 --- a/src/vs/workbench/api/browser/mainThreadCommands.ts +++ b/src/vs/workbench/api/browser/mainThreadCommands.ts @@ -8,6 +8,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { ExtHostContext, MainThreadCommandsShape, ExtHostCommandsShape, MainContext, IExtHostContext } from '../common/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { revive } from 'vs/base/common/marshalling'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @extHostNamedCustomer(MainContext.MainThreadCommands) export class MainThreadCommands implements MainThreadCommandsShape { @@ -19,6 +20,7 @@ export class MainThreadCommands implements MainThreadCommandsShape { constructor( extHostContext: IExtHostContext, @ICommandService private readonly _commandService: ICommandService, + @IExtensionService private readonly _extensionService: IExtensionService, ) { this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostCommands); @@ -70,10 +72,14 @@ export class MainThreadCommands implements MainThreadCommandsShape { } } - $executeCommand(id: string, args: any[]): Promise { + async $executeCommand(id: string, args: any[], retry: boolean): Promise { for (let i = 0; i < args.length; i++) { args[i] = revive(args[i], 0); } + if (retry && args.length > 0 && !CommandsRegistry.getCommand(id)) { + await this._extensionService.activateByEvent(`onCommand:${id}`); + throw new Error('$executeCommand:retry'); + } return this._commandService.executeCommand(id, ...args); } diff --git a/src/vs/workbench/api/browser/mainThreadDebugService.ts b/src/vs/workbench/api/browser/mainThreadDebugService.ts index de610635e2..ec635fcad1 100644 --- a/src/vs/workbench/api/browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/browser/mainThreadDebugService.ts @@ -21,7 +21,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb private readonly _proxy: ExtHostDebugServiceShape; private readonly _toDispose = new DisposableStore(); - private _breakpointEventsActive: boolean; + private _breakpointEventsActive: boolean | undefined; private readonly _debugAdapters: Map; private _debugAdaptersHandleCounter = 1; private readonly _debugConfigurationProviders: Map; @@ -35,6 +35,9 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDebugService); this._toDispose.add(debugService.onDidNewSession(session => { this._proxy.$acceptDebugSessionStarted(this.getSessionDto(session)); + this._toDispose.add(session.onDidChangeName(name => { + this._proxy.$acceptDebugSessionNameChanged(this.getSessionDto(session), name); + })); })); // Need to start listening early to new session events because a custom event can come while a session is initialising this._toDispose.add(debugService.onWillNewSession(session => { @@ -225,6 +228,13 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb }); } + public $setDebugSessionName(sessionId: DebugSessionUUID, name: string): void { + const session = this.debugService.getModel().getSession(sessionId); + if (session) { + session.setName(name); + } + } + public $customDebugAdapterRequest(sessionId: DebugSessionUUID, request: string, args: any): Promise { const session = this.debugService.getModel().getSession(sessionId, true); if (session) { @@ -351,23 +361,24 @@ class ExtensionHostDebugAdapter extends AbstractDebugAdapter { super(); } - public fireError(handle: number, err: Error) { + fireError(handle: number, err: Error) { this._onError.fire(err); } - public fireExit(handle: number, code: number, signal: string) { + fireExit(handle: number, code: number, signal: string) { this._onExit.fire(code); } - public startSession(): Promise { + startSession(): Promise { return Promise.resolve(this._proxy.$startDASession(this._handle, this._ds.getSessionDto(this._session))); } - public sendMessage(message: DebugProtocol.ProtocolMessage): void { + sendMessage(message: DebugProtocol.ProtocolMessage): void { this._proxy.$sendDAMessage(this._handle, convertToDAPaths(message, true)); } - public stopSession(): Promise { + async stopSession(): Promise { + await this.cancelPendingRequests(); return Promise.resolve(this._proxy.$stopDASession(this._handle)); } } diff --git a/src/vs/workbench/api/browser/mainThreadDecorations.ts b/src/vs/workbench/api/browser/mainThreadDecorations.ts index d8c8d73441..80aa05d61c 100644 --- a/src/vs/workbench/api/browser/mainThreadDecorations.ts +++ b/src/vs/workbench/api/browser/mainThreadDecorations.ts @@ -93,14 +93,13 @@ export class MainThreadDecorations implements MainThreadDecorationsShape { if (!data) { return undefined; } - const [weight, bubble, tooltip, letter, themeColor, source] = data; + const [weight, bubble, tooltip, letter, themeColor] = data; return { weight: weight || 0, bubble: bubble || false, color: themeColor && themeColor.id, tooltip, - letter, - source, + letter }; }); } diff --git a/src/vs/workbench/api/browser/mainThreadEditor.ts b/src/vs/workbench/api/browser/mainThreadEditor.ts index b1411d03aa..1e984c156c 100644 --- a/src/vs/workbench/api/browser/mainThreadEditor.ts +++ b/src/vs/workbench/api/browser/mainThreadEditor.ts @@ -6,7 +6,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { RenderLineNumbersType, TextEditorCursorStyle, cursorStyleToString } from 'vs/editor/common/config/editorOptions'; +import { RenderLineNumbersType, TextEditorCursorStyle, cursorStyleToString, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IRange, Range } from 'vs/editor/common/core/range'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; @@ -58,9 +58,10 @@ export class MainThreadTextEditorProperties { let cursorStyle: TextEditorCursorStyle; let lineNumbers: RenderLineNumbersType; if (codeEditor) { - const codeEditorOpts = codeEditor.getConfiguration(); - cursorStyle = codeEditorOpts.viewInfo.cursorStyle; - lineNumbers = codeEditorOpts.viewInfo.renderLineNumbers; + const options = codeEditor.getOptions(); + const lineNumbersOpts = options.get(EditorOption.lineNumbers); + cursorStyle = options.get(EditorOption.cursorStyle); + lineNumbers = lineNumbersOpts.renderType; } else if (previousProperties) { cursorStyle = previousProperties.options.cursorStyle; lineNumbers = previousProperties.options.lineNumbers; diff --git a/src/vs/workbench/api/browser/mainThreadEditors.ts b/src/vs/workbench/api/browser/mainThreadEditors.ts index 7bd901a489..42a721c3c9 100644 --- a/src/vs/workbench/api/browser/mainThreadEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadEditors.ts @@ -15,7 +15,7 @@ import { ISelection } from 'vs/editor/common/core/selection'; import { IDecorationOptions, IDecorationRenderOptions, ILineChange } from 'vs/editor/common/editorCommon'; import { ISingleEditOperation } from 'vs/editor/common/model'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IEditorOptions, ITextEditorOptions, IResourceInput } from 'vs/platform/editor/common/editor'; +import { IEditorOptions, ITextEditorOptions, IResourceInput, EditorActivation } from 'vs/platform/editor/common/editor'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors'; @@ -118,7 +118,10 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { const editorOptions: ITextEditorOptions = { preserveFocus: options.preserveFocus, pinned: options.pinned, - selection: options.selection + selection: options.selection, + // preserve pre 1.38 behaviour to not make group active when preserveFocus: true + // but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633 + activation: options.preserveFocus ? EditorActivation.RESTORE : undefined }; const input: IResourceInput = { diff --git a/src/vs/workbench/api/browser/mainThreadKeytar.ts b/src/vs/workbench/api/browser/mainThreadKeytar.ts index 1f6c748ab2..14e244f87c 100644 --- a/src/vs/workbench/api/browser/mainThreadKeytar.ts +++ b/src/vs/workbench/api/browser/mainThreadKeytar.ts @@ -31,6 +31,10 @@ export class MainThreadKeytar implements MainThreadKeytarShape { return this._credentialsService.findPassword(service); } + async $findCredentials(service: string): Promise> { + return this._credentialsService.findCredentials(service); + } + dispose(): void { // } diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index bf2f9fd7f1..a761baa83a 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -11,7 +11,7 @@ import * as search from 'vs/workbench/contrib/search/common/search'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Position as EditorPosition } from 'vs/editor/common/core/position'; import { Range as EditorRange, IRange } from 'vs/editor/common/core/range'; -import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyDto, ISuggestDataDto, ICodeActionDto } from '../common/extHost.protocol'; +import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto } from '../common/extHost.protocol'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -19,7 +19,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { URI } from 'vs/base/common/uri'; import { Selection } from 'vs/editor/common/core/selection'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; +import * as callh from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy'; import { mixin } from 'vs/base/common/objects'; @extHostNamedCustomer(MainContext.MainThreadLanguageFeatures) @@ -111,7 +111,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha return data; } - private static _reviveCallHierarchyItemDto(data: ICallHierarchyDto | undefined): callh.CallHierarchyItem { + private static _reviveCallHierarchyItemDto(data: ICallHierarchyItemDto | undefined): callh.CallHierarchyItem { if (data) { data.uri = URI.revive(data.uri); } @@ -495,21 +495,28 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha $registerCallHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void { this._registrations.set(handle, callh.CallHierarchyProviderRegistry.register(selector, { - provideCallHierarchyItem: (document, position, token) => { - return this._proxy.$provideCallHierarchyItem(handle, document.uri, position, token).then(MainThreadLanguageFeatures._reviveCallHierarchyItemDto); + provideOutgoingCalls: async (model, position, token) => { + const outgoing = await this._proxy.$provideCallHierarchyOutgoingCalls(handle, model.uri, position, token); + if (!outgoing) { + return undefined; // {{SQL CARBON EDIT}} strict-null-check + } + return outgoing.map(([item, sourceRanges]): callh.OutgoingCall => { + return { + target: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item), + sourceRanges + }; + }); }, - resolveCallHierarchyItem: (item, direction, token) => { - return this._proxy.$resolveCallHierarchyItem(handle, item, direction, token).then(data => { - if (data) { - for (let i = 0; i < data.length; i++) { - const [item, locations] = data[i]; - data[i] = [ - MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item), - MainThreadLanguageFeatures._reviveLocationDto(locations) - ]; - } - } - return data as [callh.CallHierarchyItem, modes.Location[]][]; + provideIncomingCalls: async (model, position, token) => { + const incoming = await this._proxy.$provideCallHierarchyIncomingCalls(handle, model.uri, position, token); + if (!incoming) { + return undefined; // {{SQL CARBON EDIT}} strict-null-check + } + return incoming.map(([item, sourceRanges]): callh.IncomingCall => { + return { + source: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item), + sourceRanges + }; }); } })); diff --git a/src/vs/workbench/api/browser/mainThreadMessageService.ts b/src/vs/workbench/api/browser/mainThreadMessageService.ts index 414d1b21d6..3098d9a34c 100644 --- a/src/vs/workbench/api/browser/mainThreadMessageService.ts +++ b/src/vs/workbench/api/browser/mainThreadMessageService.ts @@ -97,7 +97,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape { }); } - private _showModalMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise { + private async _showModalMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise { let cancelId: number | undefined = undefined; const buttons = commands.map((command, index) => { @@ -118,7 +118,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape { cancelId = buttons.length - 1; } - return this._dialogService.show(severity, message, buttons, { cancelId }) - .then(result => result === commands.length ? undefined : commands[result].handle); + const { choice } = await this._dialogService.show(severity, message, buttons, { cancelId }); + return choice === commands.length ? undefined : commands[choice].handle; } } diff --git a/src/vs/workbench/api/browser/mainThreadSCM.ts b/src/vs/workbench/api/browser/mainThreadSCM.ts index 89773f4934..87e1c120b6 100644 --- a/src/vs/workbench/api/browser/mainThreadSCM.ts +++ b/src/vs/workbench/api/browser/mainThreadSCM.ts @@ -198,7 +198,7 @@ class MainThreadSCMProvider implements ISCMProvider { for (const [start, deleteCount, rawResources] of groupSlices) { const resources = rawResources.map(rawResource => { - const [handle, sourceUri, icons, tooltip, strikeThrough, faded, source, letter, color] = rawResource; + const [handle, sourceUri, icons, tooltip, strikeThrough, faded] = rawResource; const icon = icons[0]; const iconDark = icons[1] || icon; const decorations = { @@ -206,10 +206,7 @@ class MainThreadSCMProvider implements ISCMProvider { iconDark: iconDark ? URI.parse(iconDark) : undefined, tooltip, strikeThrough, - faded, - source, - letter, - color: color ? color.id : undefined + faded }; return new MainThreadSCMResource( diff --git a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts index 0c49b756ff..00bdcbdf4a 100644 --- a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts @@ -10,7 +10,6 @@ import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { trimTrailingWhitespace } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand'; -import { ICodeActionsOnSaveOptions } from 'vs/editor/common/config/editorOptions'; import { EditOperation } from 'vs/editor/common/core/editOperation'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; @@ -31,13 +30,13 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; -// {{SQL CARBON EDIT}} -import { ISaveParticipant, SaveReason, IResolvedTextFileEditorModel, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; +import { ISaveParticipant, SaveReason, IResolvedTextFileEditorModel, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; // {{SQL CARBON EDIT}} import { ExtHostContext, ExtHostDocumentSaveParticipantShape, IExtHostContext } from '../common/extHost.protocol'; +import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService'; // {{SQL CARBON EDIT}} -// {{SQL CARBON EDIT}} -import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService'; - +export interface ICodeActionsOnSaveOptions { + [kind: string]: boolean; +} /* * An update participant that ensures any un-tracked changes are synced to the JSON file contents for a @@ -45,7 +44,7 @@ import { INotebookService } from 'sql/workbench/services/notebook/browser/notebo * updates the backing model in-place, this is a backup mechanism to hard-update the file before save in case * some are missed. */ -class NotebookUpdateParticipant implements ISaveParticipantParticipant { +class NotebookUpdateParticipant implements ISaveParticipantParticipant { // {{SQL CARBON EDIT}} add notebook participant constructor( @INotebookService private notebookService: INotebookService @@ -153,16 +152,12 @@ export class FinalNewLineParticipant implements ISaveParticipantParticipant { return; } - let prevSelection: Selection[] = []; + const edits = [EditOperation.insert(new Position(lineCount, model.getLineMaxColumn(lineCount)), model.getEOL())]; const editor = findEditor(model, this.codeEditorService); if (editor) { - prevSelection = editor.getSelections(); - } - - model.pushEditOperations(prevSelection, [EditOperation.insert(new Position(lineCount, model.getLineMaxColumn(lineCount)), model.getEOL())], edits => prevSelection); - - if (editor) { - editor.setSelections(prevSelection); + editor.executeEdits('insertFinalNewLine', edits, editor.getSelections()); + } else { + model.pushEditOperations([], edits, () => null); } } } @@ -276,7 +271,8 @@ class CodeActionOnSaveParticipant implements ISaveParticipant { constructor( @IBulkEditService private readonly _bulkEditService: IBulkEditService, @ICommandService private readonly _commandService: ICommandService, - @IConfigurationService private readonly _configurationService: IConfigurationService + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { } async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise { @@ -342,7 +338,7 @@ class CodeActionOnSaveParticipant implements ISaveParticipant { private async applyCodeActions(actionsToRun: readonly CodeAction[]) { for (const action of actionsToRun) { - await applyCodeAction(action, this._bulkEditService, this._commandService); + await this._instantiationService.invokeFunction(applyCodeAction, action, this._bulkEditService, this._commandService); } } diff --git a/src/vs/workbench/api/browser/mainThreadTask.ts b/src/vs/workbench/api/browser/mainThreadTask.ts index a35f8e69fb..8aa5dd3cba 100644 --- a/src/vs/workbench/api/browser/mainThreadTask.ts +++ b/src/vs/workbench/api/browser/mainThreadTask.ts @@ -626,6 +626,9 @@ export class MainThreadTask implements MainThreadTaskShape { }); }); }); + }, + getDefaultShellAndArgs: (): Promise<{ shell: string, args: string[] | string | undefined }> => { + return Promise.resolve(this._proxy.$getDefaultShellAndArgs()); } }); } diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index c05c803afb..1cdfc730bc 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -3,13 +3,13 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; -import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal'; +import { DisposableStore, Disposable } from 'vs/base/common/lifecycle'; +import { IShellLaunchConfig, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal'; import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, IShellLaunchConfigDto, TerminalLaunchConfig, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { URI } from 'vs/base/common/uri'; import { StopWatch } from 'vs/base/common/stopwatch'; -import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalInstanceService, ITerminalService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -21,7 +21,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape private readonly _toDispose = new DisposableStore(); private readonly _terminalProcesses = new Map>(); private readonly _terminalProcessesReady = new Map void>(); - private readonly _terminalOnDidWriteDataListeners = new Map(); private _dataEventTracker: TerminalDataEventTracker | undefined; constructor( @@ -131,30 +130,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape } } - /** @deprecated */ - public $registerOnDataListener(terminalId: number): void { - const terminalInstance = this._terminalService.getInstanceFromId(terminalId); - if (!terminalInstance) { - return; - } - - // Listener already registered - if (this._terminalOnDidWriteDataListeners.has(terminalId)) { - return; - } - - // Register - const listener = terminalInstance.onData(data => { - this._onTerminalData(terminalId, data); - }); - this._terminalOnDidWriteDataListeners.set(terminalId, listener); - terminalInstance.addDisposable(listener); - } - public $startSendingDataEvents(): void { if (!this._dataEventTracker) { this._dataEventTracker = this._instantiationService.createInstance(TerminalDataEventTracker, (id, data) => { - this._onTerminalData2(id, data); + this._onTerminalData(id, data); }); } } @@ -170,15 +149,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._proxy.$acceptActiveTerminalChanged(terminalId); } - /** @deprecated */ private _onTerminalData(terminalId: number, data: string): void { this._proxy.$acceptTerminalProcessData(terminalId, data); } - private _onTerminalData2(terminalId: number, data: string): void { - this._proxy.$acceptTerminalProcessData2(terminalId, data); - } - private _onTitleChanged(terminalId: number, name: string): void { this._proxy.$acceptTerminalTitleChange(terminalId, name); } diff --git a/src/vs/workbench/api/browser/mainThreadTreeViews.ts b/src/vs/workbench/api/browser/mainThreadTreeViews.ts index 01469d3733..73a9e0fbac 100644 --- a/src/vs/workbench/api/browser/mainThreadTreeViews.ts +++ b/src/vs/workbench/api/browser/mainThreadTreeViews.ts @@ -35,9 +35,11 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie this._dataProviders.set(treeViewId, dataProvider); const viewer = this.getTreeView(treeViewId); if (viewer) { - viewer.dataProvider = dataProvider; + // Order is important here. The internal tree isn't created until the dataProvider is set. + // Set all other properties first! viewer.showCollapseAllAction = !!options.showCollapseAll; viewer.canSelectMany = !!options.canSelectMany; + viewer.dataProvider = dataProvider; this.registerListeners(treeViewId, viewer); this._proxy.$setVisible(treeViewId, viewer.visible); } else { @@ -74,6 +76,13 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie } } + $setTitle(treeViewId: string, title: string): void { + const viewer = this.getTreeView(treeViewId); + if (viewer) { + viewer.title = title; + } + } + private async reveal(treeView: ITreeView, dataProvider: TreeViewDataProvider, itemIn: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise { options = options ? options : { select: false, focus: false }; const select = isUndefinedOrNull(options.select) ? false : options.select; diff --git a/src/vs/workbench/api/browser/mainThreadUrls.ts b/src/vs/workbench/api/browser/mainThreadUrls.ts index a3795d9b6a..04bd156ae8 100644 --- a/src/vs/workbench/api/browser/mainThreadUrls.ts +++ b/src/vs/workbench/api/browser/mainThreadUrls.ts @@ -8,7 +8,7 @@ import { extHostNamedCustomer } from '../common/extHostCustomers'; import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler'; +import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/common/extensionUrlHandler'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; class ExtensionUrlHandler implements IURLHandler { @@ -37,7 +37,7 @@ export class MainThreadUrls implements MainThreadUrlsShape { constructor( context: IExtHostContext, @IURLService private readonly urlService: IURLService, - @IExtensionUrlHandler private readonly inactiveExtensionUrlHandler: IExtensionUrlHandler + @IExtensionUrlHandler private readonly extensionUrlHandler: IExtensionUrlHandler ) { this.proxy = context.getProxy(ExtHostContext.ExtHostUrls); } @@ -47,7 +47,7 @@ export class MainThreadUrls implements MainThreadUrlsShape { const disposable = this.urlService.registerHandler(handler); this.handlers.set(handle, { extensionId, disposable }); - this.inactiveExtensionUrlHandler.registerExtensionHandler(extensionId, handler); + this.extensionUrlHandler.registerExtensionHandler(extensionId, handler); return Promise.resolve(undefined); } @@ -61,7 +61,7 @@ export class MainThreadUrls implements MainThreadUrlsShape { const { extensionId, disposable } = tuple; - this.inactiveExtensionUrlHandler.unregisterExtensionHandler(extensionId); + this.extensionUrlHandler.unregisterExtensionHandler(extensionId); this.handlers.delete(handle); disposable.dispose(); diff --git a/src/vs/workbench/api/browser/mainThreadWebview.ts b/src/vs/workbench/api/browser/mainThreadWebview.ts index 6c20da49c3..f3f6f482c7 100644 --- a/src/vs/workbench/api/browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/browser/mainThreadWebview.ts @@ -16,18 +16,13 @@ import { IProductService } from 'vs/platform/product/common/product'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ExtHostContext, ExtHostWebviewsShape, IExtHostContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelShowOptions, WebviewPanelViewStateData } from 'vs/workbench/api/common/extHost.protocol'; import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor'; -import { Webview } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; import { ICreateWebViewShowOptions, IWebviewEditorService, WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { extHostNamedCustomer } from '../common/extHostCustomers'; - -interface OldMainThreadWebviewState { - readonly viewType: string; - state: any; -} +import { CustomFileEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput'; /** * Bi-directional map between webview handles and inputs. @@ -78,6 +73,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews private readonly _proxy: ExtHostWebviewsShape; private readonly _webviewEditorInputs = new WebviewHandleStore(); private readonly _revivers = new Map(); + private readonly _editorProviders = new Map(); constructor( context: IExtHostContext, @@ -95,11 +91,11 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews this._register(_editorService.onDidActiveEditorChange(this.updateWebviewViewStates, this)); this._register(_editorService.onDidVisibleEditorsChange(this.updateWebviewViewStates, this)); - // This reviver's only job is to activate webview extensions + // This reviver's only job is to activate webview panel extensions // This should trigger the real reviver to be registered from the extension host side. - this._register(_webviewEditorService.registerReviver({ - canRevive: (webview: WebviewEditorInput) => { - if (!webview.webview.state) { + this._register(_webviewEditorService.registerResolver({ + canResolve: (webview: WebviewEditorInput) => { + if (!webview.webview.state && webview.getTypeId() === WebviewEditorInput.typeId) { // TODO: The typeid check is a workaround for the CustomFileEditorInput case return false; } @@ -109,7 +105,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews } return false; }, - reviveWebview: () => { throw new Error('not implemented'); } + resolveWebview: () => { throw new Error('not implemented'); } })); } @@ -154,19 +150,26 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews webview.setName(value); } + public $setState(handle: WebviewPanelHandle, state: modes.WebviewEditorState): void { + const webview = this.getWebviewEditorInput(handle); + if (webview instanceof CustomFileEditorInput) { + webview.setState(state); + } + } + public $setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void { const webview = this.getWebviewEditorInput(handle); webview.iconPath = reviveWebviewIcon(value); } public $setHtml(handle: WebviewPanelHandle, value: string): void { - const webview = this.getWebview(handle); - webview.html = value; + const webview = this.getWebviewEditorInput(handle); + webview.webview.html = value; } public $setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void { - const webview = this.getWebview(handle); - webview.contentOptions = reviveWebviewOptions(options as any /*todo@mat */); + const webview = this.getWebviewEditorInput(handle); + webview.webview.contentOptions = reviveWebviewOptions(options as any /*todo@mat */); } public $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void { @@ -182,8 +185,8 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews } public async $postMessage(handle: WebviewPanelHandle, message: any): Promise { - const webview = this.getWebview(handle); - webview.sendMessage(message); + const webview = this.getWebviewEditorInput(handle); + webview.webview.sendMessage(message); return true; } @@ -192,11 +195,11 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews throw new Error(`Reviver for ${viewType} already registered`); } - this._revivers.set(viewType, this._webviewEditorService.registerReviver({ - canRevive: (webviewEditorInput) => { + this._revivers.set(viewType, this._webviewEditorService.registerResolver({ + canResolve: (webviewEditorInput) => { return !!webviewEditorInput.webview.state && webviewEditorInput.viewType === this.getInternalWebviewViewType(viewType); }, - reviveWebview: async (webviewEditorInput): Promise => { + resolveWebview: async (webviewEditorInput): Promise => { const viewType = this.fromInternalWebviewViewType(webviewEditorInput.viewType); if (!viewType) { webviewEditorInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(webviewEditorInput.viewType); @@ -210,16 +213,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews let state = undefined; if (webviewEditorInput.webview.state) { try { - // Check for old-style webview state first which stored state inside another state object - // TODO: remove this after 1.37 ships. - if ( - typeof (webviewEditorInput.webview.state as unknown as OldMainThreadWebviewState).viewType === 'string' && - 'state' in (webviewEditorInput.webview.state as unknown as OldMainThreadWebviewState) - ) { - state = JSON.parse((webviewEditorInput.webview.state as any).state); - } else { - state = JSON.parse(webviewEditorInput.webview.state); - } + state = JSON.parse(webviewEditorInput.webview.state); } catch { // noop } @@ -245,6 +239,48 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews this._revivers.delete(viewType); } + public $registerEditorProvider(viewType: string): void { + if (this._editorProviders.has(viewType)) { + throw new Error(`Provider for ${viewType} already registered`); + } + + this._editorProviders.set(viewType, this._webviewEditorService.registerResolver({ + canResolve: (webviewEditorInput) => { + return webviewEditorInput.getTypeId() !== WebviewEditorInput.typeId && webviewEditorInput.viewType === viewType; + }, + resolveWebview: async (webview) => { + const handle = `resolved-${MainThreadWebviews.revivalPool++}`; + this._webviewEditorInputs.add(handle, webview); + this.hookupWebviewEventDelegate(handle, webview); + + try { + await this._proxy.$resolveWebviewEditor( + webview.getResource(), + handle, + viewType, + webview.getTitle(), + webview.webview.state, + editorGroupToViewColumn(this._editorGroupService, webview.group || 0), + webview.webview.options + ); + } catch (error) { + onUnexpectedError(error); + webview.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType); + } + } + })); + } + + public $unregisterEditorProvider(viewType: string): void { + const provider = this._editorProviders.get(viewType); + if (!provider) { + throw new Error(`No provider for ${viewType} registered`); + } + + provider.dispose(); + this._editorProviders.delete(viewType); + } + private getInternalWebviewViewType(viewType: string): string { return `mainThreadWebview-${viewType}`; } @@ -271,6 +307,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews } webview.webview.state = newState; }); + input.webview.onMissingCsp((extension: ExtensionIdentifier) => this._proxy.$onMissingCsp(handle, extension.value)); } private updateWebviewViewStates() { @@ -333,10 +370,6 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews return this._webviewEditorInputs.getInputForHandle(handle); } - private getWebview(handle: WebviewPanelHandle): Webview { - return this.getWebviewEditorInput(handle).webview; - } - private static getDeserializationFailedContents(viewType: string) { return ` diff --git a/src/vs/workbench/api/common/configurationExtensionPoint.ts b/src/vs/workbench/api/common/configurationExtensionPoint.ts index 6d6ecca707..08564825f6 100644 --- a/src/vs/workbench/api/common/configurationExtensionPoint.ts +++ b/src/vs/workbench/api/common/configurationExtensionPoint.ts @@ -48,7 +48,7 @@ const configurationEntrySchema: IJSONSchema = { nls.localize('scope.resource.description', "Configuration that can be configured in the user, remote, workspace or folder settings."), nls.localize('scope.machine-overridable.description', "Machine configuration that can be configured also in workspace or folder settings.") ], - description: nls.localize('scope.description', "Scope in which the configuration is applicable. Available scopes are `application`, `machine`, `window` and `resource`.") + description: nls.localize('scope.description', "Scope in which the configuration is applicable. Available scopes are `application`, `machine`, `window`, `resource` and `machine-overridable`.") }, enumDescriptions: { type: 'array', @@ -238,6 +238,7 @@ function validateProperties(configuration: IConfigurationNode, extension: IExten const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); jsonRegistry.registerSchema('vscode://schemas/workspaceConfig', { allowComments: true, + allowsTrailingCommas: true, default: { folders: [ { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 0dbfb20f78..f7f103acc3 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -517,7 +517,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I } return extHostTerminalService.createTerminalFromOptions(nameOrOptions); } - return extHostTerminalService.createTerminal(nameOrOptions, shellPath, shellArgs); + return extHostTerminalService.createTerminal(nameOrOptions, shellPath, shellArgs); }, registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider): vscode.Disposable { return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider, extension); @@ -528,6 +528,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => { return extHostWebviews.registerWebviewPanelSerializer(viewType, serializer); }, + registerWebviewEditorProvider: (viewType: string, provider: vscode.WebviewEditorProvider) => { + checkProposedApiEnabled(extension); + return extHostWebviews.registerWebviewEditorProvider(viewType, provider); + }, registerDecorationProvider(provider: vscode.DecorationProvider) { checkProposedApiEnabled(extension); return extHostDecorations.registerDecorationProvider(provider, extension.identifier); @@ -838,7 +842,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I DocumentSymbol: extHostTypes.DocumentSymbol, EndOfLine: extHostTypes.EndOfLine, EventEmitter: Emitter, - ExtensionExecutionContext: extHostTypes.ExtensionExecutionContext, ExtensionKind: extHostTypes.ExtensionKind, CustomExecution2: extHostTypes.CustomExecution2, FileChangeType: extHostTypes.FileChangeType, @@ -897,8 +900,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I ViewColumn: extHostTypes.ViewColumn, WorkspaceEdit: extHostTypes.WorkspaceEdit, // proposed - CallHierarchyDirection: extHostTypes.CallHierarchyDirection, - CallHierarchyItem: extHostTypes.CallHierarchyItem + CallHierarchyOutgoingCall: extHostTypes.CallHierarchyOutgoingCall, + CallHierarchyIncomingCall: extHostTypes.CallHierarchyIncomingCall, + CallHierarchyItem: extHostTypes.CallHierarchyItem, + Decoration: extHostTypes.Decoration, + WebviewEditorState: extHostTypes.WebviewEditorState, }; }; } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index d80c87c874..0d5ac6869d 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -39,7 +39,6 @@ import { ThemeColor } from 'vs/platform/theme/common/themeService'; 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 } from 'vs/workbench/contrib/debug/common/debug'; import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder'; import { ITerminalDimensions, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; @@ -120,7 +119,7 @@ export interface MainThreadClipboardShape extends IDisposable { export interface MainThreadCommandsShape extends IDisposable { $registerCommand(id: string): void; $unregisterCommand(id: string): void; - $executeCommand(id: string, args: any[]): Promise; + $executeCommand(id: string, args: any[], retry: boolean): Promise; $getCommands(): Promise; } @@ -248,6 +247,7 @@ export interface MainThreadTreeViewsShape extends IDisposable { $refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Promise; $reveal(treeViewId: string, treeItem: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise; $setMessage(treeViewId: string, message: string): void; + $setTitle(treeViewId: string, title: string): void; } export interface MainThreadDownloadServiceShape extends IDisposable { @@ -267,6 +267,7 @@ export interface MainThreadKeytarShape extends IDisposable { $setPassword(service: string, account: string, password: string): Promise; $deletePassword(service: string, account: string): Promise; $findPassword(service: string): Promise; + $findCredentials(service: string): Promise>; } export interface IRegExpDto { @@ -401,8 +402,6 @@ export interface MainThreadTerminalServiceShape extends IDisposable { $hide(terminalId: number): void; $sendText(terminalId: number, text: string, addNewLine: boolean): void; $show(terminalId: number, preserveFocus: boolean): void; - /** @deprecated */ - $registerOnDataListener(terminalId: number): void; $startSendingDataEvents(): void; $stopSendingDataEvents(): void; @@ -543,6 +542,7 @@ export interface MainThreadWebviewsShape extends IDisposable { $disposeWebview(handle: WebviewPanelHandle): void; $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void; $setTitle(handle: WebviewPanelHandle, value: string): void; + $setState(handle: WebviewPanelHandle, state: modes.WebviewEditorState): void; $setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void; $setHtml(handle: WebviewPanelHandle, value: string): void; @@ -551,6 +551,9 @@ export interface MainThreadWebviewsShape extends IDisposable { $registerSerializer(viewType: string): void; $unregisterSerializer(viewType: string): void; + + $registerEditorProvider(viewType: string): void; + $unregisterEditorProvider(viewType: string): void; } export interface WebviewPanelViewStateData { @@ -563,9 +566,11 @@ export interface WebviewPanelViewStateData { export interface ExtHostWebviewsShape { $onMessage(handle: WebviewPanelHandle, message: any): void; + $onMissingCsp(handle: WebviewPanelHandle, extensionId: string): void; $onDidChangeWebviewPanelViewStates(newState: WebviewPanelViewStateData): void; $onDidDisposeWebviewPanel(handle: WebviewPanelHandle): Promise; $deserializeWebviewPanel(newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise; + $resolveWebviewEditor(resource: UriComponents, newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise; } export interface MainThreadUrlsShape extends IDisposable { @@ -663,11 +668,7 @@ export type SCMRawResource = [ string[] /*icons: light, dark*/, string /*tooltip*/, boolean /*strike through*/, - boolean /*faded*/, - - string | undefined /*source*/, - string | undefined /*letter*/, - ThemeColor | null /*color*/ + boolean /*faded*/ ]; export type SCMRawResourceSplice = [ @@ -719,6 +720,7 @@ export interface MainThreadDebugServiceShape extends IDisposable { $unregisterDebugConfigurationProvider(handle: number): void; $unregisterDebugAdapterDescriptorFactory(handle: number): void; $startDebugging(folder: UriComponents | undefined, nameOrConfig: string | IDebugConfiguration, parentSessionID: string | undefined): Promise; + $setDebugSessionName(id: DebugSessionUUID, name: string): void; $customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): Promise; $appendDebugConsole(value: string): void; $startBreakpointEvents(): void; @@ -1069,8 +1071,7 @@ export interface ICodeLensDto { command?: ICommandDto; } -export interface ICallHierarchyDto { - _id: number; +export interface ICallHierarchyItemDto { kind: modes.SymbolKind; name: string; detail?: string; @@ -1113,8 +1114,8 @@ export interface ExtHostLanguageFeaturesShape { $provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise; $provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext, token: CancellationToken): Promise; $provideSelectionRanges(handle: number, resource: UriComponents, positions: IPosition[], token: CancellationToken): Promise; - $provideCallHierarchyItem(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; - $resolveCallHierarchyItem(handle: number, item: callHierarchy.CallHierarchyItem, direction: callHierarchy.CallHierarchyDirection, token: CancellationToken): Promise<[ICallHierarchyDto, modes.Location[]][]>; + $provideCallHierarchyIncomingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>; + $provideCallHierarchyOutgoingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>; } export interface ExtHostQuickOpenShape { @@ -1156,9 +1157,7 @@ export interface ExtHostTerminalServiceShape { $acceptTerminalOpened(id: number, name: string): void; $acceptActiveTerminalChanged(id: number | null): void; $acceptTerminalProcessId(id: number, processId: number): void; - /** @deprecated */ $acceptTerminalProcessData(id: number, data: string): void; - $acceptTerminalProcessData2(id: number, data: string): void; $acceptTerminalTitleChange(id: number, name: string): void; $acceptTerminalDimensions(id: number, cols: number, rows: number): void; $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void; @@ -1191,6 +1190,7 @@ export interface ExtHostTaskShape { $onDidEndTaskProcess(value: tasks.TaskProcessEndedDTO): void; $OnDidEndTask(execution: tasks.TaskExecutionDTO): void; $resolveVariables(workspaceFolder: UriComponents, toResolve: { process?: { name: string; cwd?: string }, variables: string[] }): Promise<{ process?: string; variables: { [key: string]: string } }>; + $getDefaultShellAndArgs(): Thenable<{ shell: string, args: string[] | string | undefined }>; } export interface IBreakpointDto { @@ -1266,6 +1266,7 @@ export interface ExtHostDebugServiceShape { $acceptDebugSessionActiveChanged(session: IDebugSessionDto | undefined): void; $acceptDebugSessionCustomEvent(session: IDebugSessionDto, event: any): void; $acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void; + $acceptDebugSessionNameChanged(session: IDebugSessionDto, name: string): void; } export interface DecorationRequest { @@ -1274,7 +1275,7 @@ export interface DecorationRequest { readonly uri: UriComponents; } -export type DecorationData = [number, boolean, string, string, ThemeColor, string]; +export type DecorationData = [number, boolean, string, string, ThemeColor]; export type DecorationReply = { [id: number]: DecorationData }; export interface ExtHostDecorationsShape { diff --git a/src/vs/workbench/api/common/extHostApiCommands.ts b/src/vs/workbench/api/common/extHostApiCommands.ts index 52fd9c273e..02cb4f00b2 100644 --- a/src/vs/workbench/api/common/extHostApiCommands.ts +++ b/src/vs/workbench/api/common/extHostApiCommands.ts @@ -8,7 +8,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import * as vscode from 'vscode'; import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import * as types from 'vs/workbench/api/common/extHostTypes'; -import { IRawColorInfo, IWorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol'; +import { IRawColorInfo, IWorkspaceEditDto, ICallHierarchyItemDto } from 'vs/workbench/api/common/extHost.protocol'; import { ISingleEditOperation } from 'vs/editor/common/model'; import * as modes from 'vs/editor/common/modes'; import * as search from 'vs/workbench/contrib/search/common/search'; @@ -182,6 +182,22 @@ export class ExtHostApiCommands { ], returns: 'A promise that resolves to an array of DocumentLink-instances.' }); + this._register('vscode.executeCallHierarchyProviderIncomingCalls', this._executeCallHierarchyIncomingCallsProvider, { + description: 'Execute call hierarchy provider for incoming calls', + args: [ + { name: 'uri', description: 'Uri of a text document', constraint: URI }, + { name: 'position', description: 'Position in a text document', constraint: types.Position }, + ], + returns: 'A promise that resolves to an array of CallHierarchyIncomingCall-instances.' + }); + this._register('vscode.executeCallHierarchyProviderOutgoingCalls', this._executeCallHierarchyOutgoingCallsProvider, { + description: 'Execute call hierarchy provider for outgoing calls', + args: [ + { name: 'uri', description: 'Uri of a text document', constraint: URI }, + { name: 'position', description: 'Position in a text document', constraint: types.Position }, + ], + returns: 'A promise that resolves to an array of CallHierarchyOutgoingCall-instances.' + }); this._register('vscode.executeDocumentColorProvider', this._executeDocumentColorProvider, { description: 'Execute document color provider.', args: [ @@ -557,6 +573,36 @@ export class ExtHostApiCommands { return this._commands.executeCommand('_executeLinkProvider', resource) .then(tryMapWith(typeConverters.DocumentLink.to)); } + + private async _executeCallHierarchyIncomingCallsProvider(resource: URI, position: types.Position): Promise { + type IncomingCallDto = { + source: ICallHierarchyItemDto; + sourceRanges: IRange[]; + }; + const args = { resource, position: typeConverters.Position.from(position) }; + const calls = await this._commands.executeCommand('_executeCallHierarchyIncomingCalls', args); + + const result: vscode.CallHierarchyIncomingCall[] = []; + for (const call of calls) { + result.push(new types.CallHierarchyIncomingCall(typeConverters.CallHierarchyItem.to(call.source), call.sourceRanges.map(typeConverters.Range.to))); + } + return result; + } + + private async _executeCallHierarchyOutgoingCallsProvider(resource: URI, position: types.Position): Promise { + type OutgoingCallDto = { + sourceRanges: IRange[]; + target: ICallHierarchyItemDto; + }; + const args = { resource, position: typeConverters.Position.from(position) }; + const calls = await this._commands.executeCommand('_executeCallHierarchyOutgoingCalls', args); + + const result: vscode.CallHierarchyOutgoingCall[] = []; + for (const call of calls) { + result.push(new types.CallHierarchyOutgoingCall(typeConverters.CallHierarchyItem.to(call.target), call.sourceRanges.map(typeConverters.Range.to))); + } + return result; + } } function tryMapWith(f: (x: T) => R) { diff --git a/src/vs/workbench/api/common/extHostCommands.ts b/src/vs/workbench/api/common/extHostCommands.ts index d2d42b1b80..609b505c93 100644 --- a/src/vs/workbench/api/common/extHostCommands.ts +++ b/src/vs/workbench/api/common/extHostCommands.ts @@ -33,7 +33,7 @@ export interface ArgumentProcessor { export class ExtHostCommands implements ExtHostCommandsShape { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; private readonly _commands = new Map(); private readonly _proxy: MainThreadCommandsShape; @@ -112,6 +112,10 @@ export class ExtHostCommands implements ExtHostCommandsShape { executeCommand(id: string, ...args: any[]): Promise { this._logService.trace('ExtHostCommands#executeCommand', id); + return this._doExecuteCommand(id, args, true); + } + + private async _doExecuteCommand(id: string, args: any[], retry: boolean): Promise { if (this._commands.has(id)) { // we stay inside the extension host and support @@ -120,8 +124,7 @@ export class ExtHostCommands implements ExtHostCommandsShape { } else { // automagically convert some argument types - - args = cloneAndChange(args, function (value) { + const toArgs = cloneAndChange(args, function (value) { if (value instanceof extHostTypes.Position) { return extHostTypeConverter.Position.from(value); } @@ -136,7 +139,19 @@ export class ExtHostCommands implements ExtHostCommandsShape { } }); - return this._proxy.$executeCommand(id, args).then(result => revive(result, 0)); + try { + const result = await this._proxy.$executeCommand(id, toArgs, retry); + return revive(result, 0); + } catch (e) { + // Rerun the command when it wasn't known, had arguments, and when retry + // is enabled. We do this because the command might be registered inside + // the extension host now and can therfore accept the arguments as-is. + if (e instanceof Error && e.message === '$executeCommand:retry') { + return this._doExecuteCommand(id, args, false); + } else { + throw e; + } + } } } diff --git a/src/vs/workbench/api/common/extHostConfiguration.ts b/src/vs/workbench/api/common/extHostConfiguration.ts index 30c26aa39b..476df18c51 100644 --- a/src/vs/workbench/api/common/extHostConfiguration.ts +++ b/src/vs/workbench/api/common/extHostConfiguration.ts @@ -42,7 +42,7 @@ type ConfigurationInspect = { export class ExtHostConfiguration implements ExtHostConfigurationShape { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; private readonly _proxy: MainThreadConfigurationShape; private readonly _extHostWorkspace: ExtHostWorkspace; diff --git a/src/vs/workbench/api/common/extHostDebugService.ts b/src/vs/workbench/api/common/extHostDebugService.ts index 737960abea..708bd00980 100644 --- a/src/vs/workbench/api/common/extHostDebugService.ts +++ b/src/vs/workbench/api/common/extHostDebugService.ts @@ -13,7 +13,7 @@ export const IExtHostDebugService = createDecorator('IExtH export interface IExtHostDebugService extends ExtHostDebugServiceShape { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; onDidStartDebugSession: Event; onDidTerminateDebugSession: Event; diff --git a/src/vs/workbench/api/common/extHostDecorations.ts b/src/vs/workbench/api/common/extHostDecorations.ts index 3af0d8259d..507eaca490 100644 --- a/src/vs/workbench/api/common/extHostDecorations.ts +++ b/src/vs/workbench/api/common/extHostDecorations.ts @@ -6,7 +6,7 @@ import * as vscode from 'vscode'; import { URI } from 'vs/base/common/uri'; import { MainContext, ExtHostDecorationsShape, MainThreadDecorationsShape, DecorationData, DecorationRequest, DecorationReply } from 'vs/workbench/api/common/extHost.protocol'; -import { Disposable } from 'vs/workbench/api/common/extHostTypes'; +import { Disposable, Decoration } from 'vs/workbench/api/common/extHostTypes'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { asArray } from 'vs/base/common/arrays'; @@ -59,12 +59,14 @@ export class ExtHostDecorations implements IExtHostDecorations { } const { provider, extensionId } = entry; return Promise.resolve(provider.provideDecoration(URI.revive(uri), token)).then(data => { - if (data && data.letter && data.letter.length !== 1) { - console.warn(`INVALID decoration from extension '${extensionId.value}'. The 'letter' must be set and be one character, not '${data.letter}'.`); + if (!data) { + return; } - if (data) { - result[id] = [data.priority, data.bubble, data.title, data.letter, data.color, data.source]; - + try { + Decoration.validate(data); + result[id] = [data.priority, data.bubble, data.title, data.letter, data.color]; + } catch (e) { + console.warn(`INVALID decoration from extension '${extensionId.value}': ${e}`); } }, err => { console.error(err); diff --git a/src/vs/workbench/api/common/extHostDocumentsAndEditors.ts b/src/vs/workbench/api/common/extHostDocumentsAndEditors.ts index 35bfa5bc86..2472bf9105 100644 --- a/src/vs/workbench/api/common/extHostDocumentsAndEditors.ts +++ b/src/vs/workbench/api/common/extHostDocumentsAndEditors.ts @@ -17,7 +17,7 @@ import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsShape { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; private _disposables: Disposable[] = []; diff --git a/src/vs/workbench/api/common/extHostExtensionActivator.ts b/src/vs/workbench/api/common/extHostExtensionActivator.ts index b1daaeda35..c39b99e46e 100644 --- a/src/vs/workbench/api/common/extHostExtensionActivator.ts +++ b/src/vs/workbench/api/common/extHostExtensionActivator.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; +import * as vscode from 'vscode'; import { IDisposable } from 'vs/base/common/lifecycle'; import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; @@ -11,29 +12,11 @@ import { ExtensionActivationError, MissingDependencyError } from 'vs/workbench/s const NO_OP_VOID_PROMISE = Promise.resolve(undefined); -export interface IExtensionMemento { - get(key: string): T | undefined; - get(key: string, defaultValue: T): T; - update(key: string, value: any): Promise; -} - -export interface IExtensionContext { - subscriptions: IDisposable[]; - workspaceState: IExtensionMemento; - globalState: IExtensionMemento; - extensionPath: string; - storagePath: string; - globalStoragePath: string; - asAbsolutePath(relativePath: string): string; - readonly logPath: string; - executionContext: number; -} - /** * Represents the source code (module) of an extension. */ export interface IExtensionModule { - activate?(ctx: IExtensionContext): Promise; + activate?(ctx: vscode.ExtensionContext): Promise; deactivate?(): void; } diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts index 8836b32bee..e8a05f05d2 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -13,7 +13,7 @@ import { URI } from 'vs/base/common/uri'; import { ILogService } from 'vs/platform/log/common/log'; import { ExtHostExtensionServiceShape, IInitData, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape, IResolveAuthorityResult } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration'; -import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator'; +import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator'; import { ExtHostStorage, IExtHostStorage } from 'vs/workbench/api/common/extHostStorage'; import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions'; @@ -25,7 +25,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio import { Schemas } from 'vs/base/common/network'; import { VSBuffer } from 'vs/base/common/buffer'; import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento'; -import { RemoteAuthorityResolverError, ExtensionExecutionContext } from 'vs/workbench/api/common/extHostTypes'; +import { RemoteAuthorityResolverError } from 'vs/workbench/api/common/extHostTypes'; import { ResolvedAuthority, ResolvedOptions } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; @@ -64,7 +64,7 @@ type TelemetryActivationEventFragment = { export abstract class AbstractExtHostExtensionService implements ExtHostExtensionServiceShape { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; private static readonly WORKSPACE_CONTAINS_TIMEOUT = 7000; @@ -331,11 +331,11 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio this._logService.info(`ExtensionService#_doActivateExtension ${extensionDescription.identifier.value} ${JSON.stringify(reason)}`); const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup); - return Promise.all([ - this._loadCommonJSModule(joinPath(extensionDescription.extensionLocation, extensionDescription.main), activationTimesBuilder), + return Promise.all([ + this._loadCommonJSModule(joinPath(extensionDescription.extensionLocation, extensionDescription.main), activationTimesBuilder), this._loadExtensionContext(extensionDescription) ]).then(values => { - return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, values[0], values[1], activationTimesBuilder); + return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, values[0], values[1], activationTimesBuilder); }); } @@ -353,7 +353,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio this._storagePath.whenReady ]).then(() => { const that = this; - return Object.freeze({ + return Object.freeze({ globalState, workspaceState, subscriptions: [], @@ -361,13 +361,12 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio get storagePath() { return that._storagePath.workspaceValue(extensionDescription); }, get globalStoragePath() { return that._storagePath.globalValue(extensionDescription); }, asAbsolutePath: (relativePath: string) => { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); }, - get logPath() { return path.join(that._initData.logsLocation.fsPath, extensionDescription.identifier.value); }, - executionContext: this._initData.remote.isRemote ? ExtensionExecutionContext.Remote : ExtensionExecutionContext.Local, + get logPath() { return path.join(that._initData.logsLocation.fsPath, extensionDescription.identifier.value); } }); }); } - private static _callActivate(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: IExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { + private static _callActivate(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: vscode.ExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { // Make sure the extension's surface is not undefined extensionModule = extensionModule || { activate: undefined, @@ -379,7 +378,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio }); } - private static _callActivateOptional(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: IExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { + private static _callActivateOptional(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: vscode.ExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { if (typeof extensionModule.activate === 'function') { try { activationTimesBuilder.activateCallStart(); @@ -767,7 +766,7 @@ function getTelemetryActivationEvent(extensionDescription: IExtensionDescription export const IExtHostExtensionService = createDecorator('IExtHostExtensionService'); export interface IExtHostExtensionService extends AbstractExtHostExtensionService { - _serviceBrand: any; + _serviceBrand: undefined; initialize(): Promise; isActivated(extensionId: ExtensionIdentifier): boolean; activateByIdWithErrors(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise; diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 604a6a2663..a09a616aaf 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -14,7 +14,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/common/extHostCommands'; import { ExtHostDiagnostics } from 'vs/workbench/api/common/extHostDiagnostics'; import { asPromise } from 'vs/base/common/async'; -import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, IRawColorInfo, IMainContext, IdObject, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILanguageConfigurationDto, IWorkspaceSymbolDto, ISuggestResultDto, IWorkspaceSymbolsDto, ICodeActionDto, IDocumentFilterDto, IWorkspaceEditDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICodeLensDto, ISuggestDataDto, ILinksListDto, ChainedCacheId, ICodeLensListDto, ICodeActionListDto, ISignatureHelpDto, ISignatureHelpContextDto } from './extHost.protocol'; +import * as extHostProtocol from './extHost.protocol'; import { regExpLeadsToEndlessLoop, regExpFlags } from 'vs/base/common/strings'; import { IPosition } from 'vs/editor/common/core/position'; import { IRange, Range as EditorRange } from 'vs/editor/common/core/range'; @@ -24,8 +24,6 @@ import { ISelection, Selection } from 'vs/editor/common/core/selection'; import { ILogService } from 'vs/platform/log/common/log'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; -import { LRUCache } from 'vs/base/common/map'; import { IURITransformer } from 'vs/base/common/uriIpc'; import { DisposableStore, dispose } from 'vs/base/common/lifecycle'; @@ -67,10 +65,10 @@ class DocumentSymbolAdapter { const res: modes.DocumentSymbol[] = []; const parentStack: modes.DocumentSymbol[] = []; for (const info of infos) { - const element = { + const element: modes.DocumentSymbol = { name: info.name || '!!MISSING: name!!', kind: typeConvert.SymbolKind.from(info.kind), - tags: info.tags && info.tags.map(typeConvert.SymbolTag.from), + tags: info.tags ? info.tags.map(typeConvert.SymbolTag.from) : [], detail: '', containerName: info.containerName, range: typeConvert.Range.from(info.location.range), @@ -112,7 +110,7 @@ class CodeLensAdapter { private readonly _provider: vscode.CodeLensProvider ) { } - provideCodeLenses(resource: URI, token: CancellationToken): Promise { + provideCodeLenses(resource: URI, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); return asPromise(() => this._provider.provideCodeLenses(doc, token)).then(lenses => { @@ -125,7 +123,7 @@ class CodeLensAdapter { const disposables = new DisposableStore(); this._disposables.set(cacheId, disposables); - const result: ICodeLensListDto = { + const result: extHostProtocol.ICodeLensListDto = { cacheId, lenses: [], }; @@ -142,7 +140,7 @@ class CodeLensAdapter { }); } - resolveCodeLens(symbol: ICodeLensDto, token: CancellationToken): Promise { + resolveCodeLens(symbol: extHostProtocol.ICodeLensDto, token: CancellationToken): Promise { const lens = symbol.cacheId && this._cache.get(...symbol.cacheId); if (!lens) { @@ -309,7 +307,7 @@ class ReferenceAdapter { } } -export interface CustomCodeAction extends ICodeActionDto { +export interface CustomCodeAction extends extHostProtocol.ICodeActionDto { _isSynthetic?: boolean; } @@ -328,7 +326,7 @@ class CodeActionAdapter { private readonly _extensionId: ExtensionIdentifier ) { } - provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise { + provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); const ran = Selection.isISelection(rangeOrSelection) @@ -392,7 +390,7 @@ class CodeActionAdapter { } } - return { cacheId, actions }; + return { cacheId, actions }; }); } @@ -481,8 +479,8 @@ class NavigateTypeAdapter { this._provider = provider; } - provideWorkspaceSymbols(search: string, token: CancellationToken): Promise { - const result: IWorkspaceSymbolsDto = IdObject.mixin({ symbols: [] }); + provideWorkspaceSymbols(search: string, token: CancellationToken): Promise { + const result: extHostProtocol.IWorkspaceSymbolsDto = extHostProtocol.IdObject.mixin({ symbols: [] }); return asPromise(() => this._provider.provideWorkspaceSymbols(search, token)).then(value => { if (isNonEmptyArray(value)) { for (const item of value) { @@ -494,7 +492,7 @@ class NavigateTypeAdapter { console.warn('INVALID SymbolInformation, lacks name', item); continue; } - const symbol = IdObject.mixin(typeConvert.WorkspaceSymbol.from(item)); + const symbol = extHostProtocol.IdObject.mixin(typeConvert.WorkspaceSymbol.from(item)); this._symbolCache[symbol._id!] = item; result.symbols.push(symbol); } @@ -507,7 +505,7 @@ class NavigateTypeAdapter { }); } - resolveWorkspaceSymbol(symbol: IWorkspaceSymbolDto, token: CancellationToken): Promise { + resolveWorkspaceSymbol(symbol: extHostProtocol.IWorkspaceSymbolDto, token: CancellationToken): Promise { if (typeof this._provider.resolveWorkspaceSymbol !== 'function') { return Promise.resolve(symbol); @@ -544,7 +542,7 @@ class RenameAdapter { private readonly _provider: vscode.RenameProvider ) { } - provideRenameEdits(resource: URI, position: IPosition, newName: string, token: CancellationToken): Promise { + provideRenameEdits(resource: URI, position: IPosition, newName: string, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); const pos = typeConvert.Position.to(position); @@ -557,10 +555,10 @@ class RenameAdapter { }, err => { const rejectReason = RenameAdapter._asMessage(err); if (rejectReason) { - return { rejectReason, edits: undefined! }; + return { rejectReason, edits: undefined! }; } else { // generic error - return Promise.reject(err); + return Promise.reject(err); } }); } @@ -634,7 +632,7 @@ class SuggestAdapter { this._provider = provider; } - provideCompletionItems(resource: URI, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise { + provideCompletionItems(resource: URI, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); const pos = typeConvert.Position.to(position); @@ -663,7 +661,7 @@ class SuggestAdapter { const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) as Range || new Range(pos, pos)) .with({ end: pos }); - const result: ISuggestResultDto = { + const result: extHostProtocol.ISuggestResultDto = { x: pid, b: [], a: typeConvert.Range.from(wordRangeBeforePos), @@ -683,7 +681,7 @@ class SuggestAdapter { }); } - resolveCompletionItem(_resource: URI, position: IPosition, id: ChainedCacheId, token: CancellationToken): Promise { + resolveCompletionItem(_resource: URI, position: IPosition, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise { if (typeof this._provider.resolveCompletionItem !== 'function') { return Promise.resolve(undefined); @@ -711,7 +709,7 @@ class SuggestAdapter { this._cache.delete(id); } - private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, id: ChainedCacheId): ISuggestDataDto | undefined { + private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, id: extHostProtocol.ChainedCacheId): extHostProtocol.ISuggestDataDto | undefined { if (typeof item.label !== 'string' || item.label.length === 0) { console.warn('INVALID text edit -> must have at least a label'); return undefined; @@ -722,7 +720,7 @@ class SuggestAdapter { throw Error('DisposableStore is missing...'); } - const result: ISuggestDataDto = { + const result: extHostProtocol.ISuggestDataDto = { // x: id, // @@ -779,7 +777,7 @@ class SignatureHelpAdapter { private readonly _provider: vscode.SignatureHelpProvider, ) { } - provideSignatureHelp(resource: URI, position: IPosition, context: ISignatureHelpContextDto, token: CancellationToken): Promise { + provideSignatureHelp(resource: URI, position: IPosition, context: extHostProtocol.ISignatureHelpContextDto, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); const pos = typeConvert.Position.to(position); const vscodeContext = this.reviveContext(context); @@ -793,7 +791,7 @@ class SignatureHelpAdapter { }); } - private reviveContext(context: ISignatureHelpContextDto): vscode.SignatureHelpContext { + private reviveContext(context: extHostProtocol.ISignatureHelpContextDto): vscode.SignatureHelpContext { let activeSignatureHelp: vscode.SignatureHelp | undefined = undefined; if (context.activeSignatureHelp) { const revivedSignatureHelp = typeConvert.SignatureHelp.to(context.activeSignatureHelp); @@ -857,7 +855,7 @@ class LinkProviderAdapter { private readonly _provider: vscode.DocumentLinkProvider ) { } - provideLinks(resource: URI, token: CancellationToken): Promise { + provideLinks(resource: URI, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); return asPromise(() => this._provider.provideDocumentLinks(doc, token)).then(links => { @@ -879,9 +877,9 @@ class LinkProviderAdapter { } else { // cache links for future resolving const pid = this._cache.add(links); - const result: ILinksListDto = { links: [], id: pid }; + const result: extHostProtocol.ILinksListDto = { links: [], id: pid }; for (let i = 0; i < links.length; i++) { - const dto: ILinkDto = typeConvert.DocumentLink.from(links[i]); + const dto: extHostProtocol.ILinkDto = typeConvert.DocumentLink.from(links[i]); dto.cacheId = [pid, i]; result.links.push(dto); } @@ -890,7 +888,7 @@ class LinkProviderAdapter { }); } - resolveLink(id: ChainedCacheId, token: CancellationToken): Promise { + resolveLink(id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise { if (typeof this._provider.resolveDocumentLink !== 'function') { return Promise.resolve(undefined); } @@ -915,14 +913,14 @@ class ColorProviderAdapter { private _provider: vscode.DocumentColorProvider ) { } - provideColors(resource: URI, token: CancellationToken): Promise { + provideColors(resource: URI, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); return asPromise(() => this._provider.provideDocumentColors(doc, token)).then(colors => { if (!Array.isArray(colors)) { return []; } - const colorInfos: IRawColorInfo[] = colors.map(ci => { + const colorInfos: extHostProtocol.IRawColorInfo[] = colors.map(ci => { return { color: typeConvert.Color.from(ci.color), range: typeConvert.Range.from(ci.range) @@ -933,7 +931,7 @@ class ColorProviderAdapter { }); } - provideColorPresentations(resource: URI, raw: IRawColorInfo, token: CancellationToken): Promise { + provideColorPresentations(resource: URI, raw: extHostProtocol.IRawColorInfo, token: CancellationToken): Promise { const document = this._documents.getDocument(resource); const range = typeConvert.Range.to(raw.range); const color = typeConvert.Color.to(raw.color); @@ -1011,56 +1009,29 @@ class SelectionRangeAdapter { class CallHierarchyAdapter { - // todo@joh keep object (heap service, lifecycle) - private readonly _cache = new LRUCache(1000, 0.8); - private _idPool = 0; - constructor( private readonly _documents: ExtHostDocuments, private readonly _provider: vscode.CallHierarchyItemProvider ) { } - provideCallHierarchyItem(resource: URI, pos: IPosition, token: CancellationToken): Promise { - const document = this._documents.getDocument(resource); - const position = typeConvert.Position.to(pos); - - return asPromise(() => this._provider.provideCallHierarchyItem(document, position, token)).then(item => { - if (!item) { - return undefined; - } - return this._fromItem(item); - }); + async provideCallsTo(uri: URI, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> { + const doc = this._documents.getDocument(uri); + const pos = typeConvert.Position.to(position); + const calls = await this._provider.provideCallHierarchyIncomingCalls(doc, pos, token); + if (!calls) { + return undefined; + } + return calls.map(call => (<[extHostProtocol.ICallHierarchyItemDto, IRange[]]>[typeConvert.CallHierarchyItem.from(call.source), call.sourceRanges.map(typeConvert.Range.from)])); } - resolveCallHierarchyItem(item: callHierarchy.CallHierarchyItem, direction: callHierarchy.CallHierarchyDirection, token: CancellationToken): Promise<[callHierarchy.CallHierarchyItem, modes.Location[]][]> { - return asPromise(() => this._provider.resolveCallHierarchyItem( - this._cache.get(item._id)!, - direction as number, token) // todo@joh proper convert - ).then(data => { - if (!data) { - return []; - } - return data.map(tuple => { - return <[callHierarchy.CallHierarchyItem, modes.Location[]]>[ - this._fromItem(tuple[0]), - tuple[1].map(typeConvert.location.from) - ]; - }); - }); - } - - private _fromItem(item: vscode.CallHierarchyItem, _id: number = this._idPool++): callHierarchy.CallHierarchyItem { - const res = { - _id, - name: item.name, - detail: item.detail, - kind: typeConvert.SymbolKind.from(item.kind), - uri: item.uri, - range: typeConvert.Range.from(item.range), - selectionRange: typeConvert.Range.from(item.selectionRange), - }; - this._cache.set(_id, item); - return res; + async provideCallsFrom(uri: URI, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> { + const doc = this._documents.getDocument(uri); + const pos = typeConvert.Position.to(position); + const calls = await this._provider.provideCallHierarchyOutgoingCalls(doc, pos, token); + if (!calls) { + return undefined; + } + return calls.map(call => (<[extHostProtocol.ICallHierarchyItemDto, IRange[]]>[typeConvert.CallHierarchyItem.from(call.target), call.sourceRanges.map(typeConvert.Range.from)])); } } @@ -1077,12 +1048,12 @@ class AdapterData { ) { } } -export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { +export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageFeaturesShape { private static _handlePool: number = 0; private readonly _uriTransformer: IURITransformer | null; - private _proxy: MainThreadLanguageFeaturesShape; + private _proxy: extHostProtocol.MainThreadLanguageFeaturesShape; private _documents: ExtHostDocuments; private _commands: ExtHostCommands; private _diagnostics: ExtHostDiagnostics; @@ -1090,7 +1061,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { private readonly _logService: ILogService; constructor( - mainContext: IMainContext, + mainContext: extHostProtocol.IMainContext, uriTransformer: IURITransformer | null, documents: ExtHostDocuments, commands: ExtHostCommands, @@ -1098,18 +1069,18 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { logService: ILogService ) { this._uriTransformer = uriTransformer; - this._proxy = mainContext.getProxy(MainContext.MainThreadLanguageFeatures); + this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadLanguageFeatures); this._documents = documents; this._commands = commands; this._diagnostics = diagnostics; this._logService = logService; } - private _transformDocumentSelector(selector: vscode.DocumentSelector): Array { + private _transformDocumentSelector(selector: vscode.DocumentSelector): Array { return coalesce(asArray(selector).map(sel => this._doTransformDocumentSelector(sel))); } - private _doTransformDocumentSelector(selector: string | vscode.DocumentFilter): IDocumentFilterDto | undefined { + private _doTransformDocumentSelector(selector: string | vscode.DocumentFilter): extHostProtocol.IDocumentFilterDto | undefined { if (typeof selector === 'string') { return { $serialized: true, @@ -1217,11 +1188,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return result; } - $provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise { + $provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise { return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource), token), undefined); } - $resolveCodeLens(handle: number, symbol: ICodeLensDto, token: CancellationToken): Promise { + $resolveCodeLens(handle: number, symbol: extHostProtocol.ICodeLensDto, token: CancellationToken): Promise { return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(symbol, token), undefined); } @@ -1316,7 +1287,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { } - $provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise { + $provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise { return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(URI.revive(resource), rangeOrSelection, context, token), undefined); } @@ -1364,11 +1335,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideWorkspaceSymbols(handle: number, search: string, token: CancellationToken): Promise { + $provideWorkspaceSymbols(handle: number, search: string, token: CancellationToken): Promise { return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search, token), { symbols: [] }); } - $resolveWorkspaceSymbol(handle: number, symbol: IWorkspaceSymbolDto, token: CancellationToken): Promise { + $resolveWorkspaceSymbol(handle: number, symbol: extHostProtocol.IWorkspaceSymbolDto, token: CancellationToken): Promise { return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol, token), undefined); } @@ -1384,7 +1355,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise { + $provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise { return this._withAdapter(handle, RenameAdapter, adapter => adapter.provideRenameEdits(URI.revive(resource), position, newName, token), undefined); } @@ -1400,11 +1371,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise { + $provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise { return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(URI.revive(resource), position, context, token), undefined); } - $resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, id: ChainedCacheId, token: CancellationToken): Promise { + $resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise { return this._withAdapter(handle, SuggestAdapter, adapter => adapter.resolveCompletionItem(URI.revive(resource), position, id, token), undefined); } @@ -1415,7 +1386,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { // --- parameter hints registerSignatureHelpProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, metadataOrTriggerChars: string[] | vscode.SignatureHelpProviderMetadata): vscode.Disposable { - const metadata: ISignatureHelpProviderMetadataDto | undefined = Array.isArray(metadataOrTriggerChars) + const metadata: extHostProtocol.ISignatureHelpProviderMetadataDto | undefined = Array.isArray(metadataOrTriggerChars) ? { triggerCharacters: metadataOrTriggerChars, retriggerCharacters: [] } : metadataOrTriggerChars; @@ -1424,7 +1395,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: ISignatureHelpContextDto, token: CancellationToken): Promise { + $provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: extHostProtocol.ISignatureHelpContextDto, token: CancellationToken): Promise { return this._withAdapter(handle, SignatureHelpAdapter, adapter => adapter.provideSignatureHelp(URI.revive(resource), position, context, token), undefined); } @@ -1440,11 +1411,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise { + $provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise { return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.provideLinks(URI.revive(resource), token), undefined); } - $resolveDocumentLink(handle: number, id: ChainedCacheId, token: CancellationToken): Promise { + $resolveDocumentLink(handle: number, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise { return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.resolveLink(id, token), undefined); } @@ -1458,11 +1429,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideDocumentColors(handle: number, resource: UriComponents, token: CancellationToken): Promise { + $provideDocumentColors(handle: number, resource: UriComponents, token: CancellationToken): Promise { return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColors(URI.revive(resource), token), []); } - $provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise { + $provideColorPresentations(handle: number, resource: UriComponents, colorInfo: extHostProtocol.IRawColorInfo, token: CancellationToken): Promise { return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(URI.revive(resource), colorInfo, token), undefined); } @@ -1496,24 +1467,24 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideCallHierarchyItem(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise { - return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallHierarchyItem(URI.revive(resource), position, token), undefined); + $provideCallHierarchyIncomingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> { + return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsTo(URI.revive(resource), position, token), undefined); } - $resolveCallHierarchyItem(handle: number, item: callHierarchy.CallHierarchyItem, direction: callHierarchy.CallHierarchyDirection, token: CancellationToken): Promise<[callHierarchy.CallHierarchyItem, modes.Location[]][]> { - return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.resolveCallHierarchyItem(item, direction, token), []); + $provideCallHierarchyOutgoingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> { + return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsFrom(URI.revive(resource), position, token), undefined); } // --- configuration - private static _serializeRegExp(regExp: RegExp): IRegExpDto { + private static _serializeRegExp(regExp: RegExp): extHostProtocol.IRegExpDto { return { pattern: regExp.source, flags: regExpFlags(regExp), }; } - private static _serializeIndentationRule(indentationRule: vscode.IndentationRule): IIndentationRuleDto { + private static _serializeIndentationRule(indentationRule: vscode.IndentationRule): extHostProtocol.IIndentationRuleDto { return { decreaseIndentPattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.decreaseIndentPattern), increaseIndentPattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.increaseIndentPattern), @@ -1522,7 +1493,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { }; } - private static _serializeOnEnterRule(onEnterRule: vscode.OnEnterRule): IOnEnterRuleDto { + private static _serializeOnEnterRule(onEnterRule: vscode.OnEnterRule): extHostProtocol.IOnEnterRuleDto { return { beforeText: ExtHostLanguageFeatures._serializeRegExp(onEnterRule.beforeText), afterText: onEnterRule.afterText ? ExtHostLanguageFeatures._serializeRegExp(onEnterRule.afterText) : undefined, @@ -1531,7 +1502,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { }; } - private static _serializeOnEnterRules(onEnterRules: vscode.OnEnterRule[]): IOnEnterRuleDto[] { + private static _serializeOnEnterRules(onEnterRules: vscode.OnEnterRule[]): extHostProtocol.IOnEnterRuleDto[] { return onEnterRules.map(ExtHostLanguageFeatures._serializeOnEnterRule); } @@ -1551,7 +1522,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { } const handle = this._nextHandle(); - const serializedConfiguration: ILanguageConfigurationDto = { + const serializedConfiguration: extHostProtocol.ILanguageConfigurationDto = { comments: configuration.comments, brackets: configuration.brackets, wordPattern: configuration.wordPattern ? ExtHostLanguageFeatures._serializeRegExp(configuration.wordPattern) : undefined, diff --git a/src/vs/workbench/api/common/extHostMemento.ts b/src/vs/workbench/api/common/extHostMemento.ts index ffcddef87f..669b9d11f2 100644 --- a/src/vs/workbench/api/common/extHostMemento.ts +++ b/src/vs/workbench/api/common/extHostMemento.ts @@ -3,11 +3,11 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as vscode from 'vscode'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { IExtensionMemento } from 'vs/workbench/api/common/extHostExtensionActivator'; import { ExtHostStorage } from 'vs/workbench/api/common/extHostStorage'; -export class ExtensionMemento implements IExtensionMemento { +export class ExtensionMemento implements vscode.Memento { private readonly _id: string; private readonly _shared: boolean; diff --git a/src/vs/workbench/api/common/extHostOutput.ts b/src/vs/workbench/api/common/extHostOutput.ts index 02bc7b4b1a..22389c5020 100644 --- a/src/vs/workbench/api/common/extHostOutput.ts +++ b/src/vs/workbench/api/common/extHostOutput.ts @@ -7,7 +7,7 @@ import { MainContext, MainThreadOutputServiceShape, ExtHostOutputServiceShape } import * as vscode from 'vscode'; import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; -import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { VSBuffer } from 'vs/base/common/buffer'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; @@ -137,23 +137,15 @@ export class LazyOutputChannel implements vscode.OutputChannel { export class ExtHostOutputService implements ExtHostOutputServiceShape { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; protected readonly _proxy: MainThreadOutputServiceShape; - protected readonly _channels: Map = new Map(); - protected readonly _visibleChannelDisposable = new MutableDisposable(); constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService) { this._proxy = extHostRpc.getProxy(MainContext.MainThreadOutputService); } $setVisibleChannel(channelId: string): void { - if (channelId) { - const channel = this._channels.get(channelId); - if (channel) { - this._visibleChannelDisposable.value = channel.onDidAppend(() => channel.update()); - } - } } createOutputChannel(name: string): vscode.OutputChannel { diff --git a/src/vs/workbench/api/common/extHostRequireInterceptor.ts b/src/vs/workbench/api/common/extHostRequireInterceptor.ts index 1a7bd52c3e..6a1cb5a048 100644 --- a/src/vs/workbench/api/common/extHostRequireInterceptor.ts +++ b/src/vs/workbench/api/common/extHostRequireInterceptor.ts @@ -134,6 +134,7 @@ interface IKeytarModule { setPassword(service: string, account: string, password: string): Promise; deletePassword(service: string, account: string): Promise; findPassword(service: string): Promise; + findCredentials(service: string): Promise>; } class KeytarNodeModuleFactory implements INodeModuleFactory { @@ -174,6 +175,9 @@ class KeytarNodeModuleFactory implements INodeModuleFactory { }, findPassword: (service: string): Promise => { return mainThreadKeytar.$findPassword(service); + }, + findCredentials(service: string): Promise> { + return mainThreadKeytar.$findCredentials(service); } }; } diff --git a/src/vs/workbench/api/common/extHostRpcService.ts b/src/vs/workbench/api/common/extHostRpcService.ts index 6e4d351083..10e46fd3ef 100644 --- a/src/vs/workbench/api/common/extHostRpcService.ts +++ b/src/vs/workbench/api/common/extHostRpcService.ts @@ -9,11 +9,11 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export const IExtHostRpcService = createDecorator('IExtHostRpcService'); export interface IExtHostRpcService extends IRPCProtocol { - _serviceBrand: any; + _serviceBrand: undefined; } export class ExtHostRpcService implements IExtHostRpcService { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; readonly getProxy: (identifier: ProxyIdentifier) => T; readonly set: (identifier: ProxyIdentifier, instance: R) => R; diff --git a/src/vs/workbench/api/common/extHostSCM.ts b/src/vs/workbench/api/common/extHostSCM.ts index e2ec5628f7..67b56749c1 100644 --- a/src/vs/workbench/api/common/extHostSCM.ts +++ b/src/vs/workbench/api/common/extHostSCM.ts @@ -319,11 +319,7 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG const strikeThrough = r.decorations && !!r.decorations.strikeThrough; const faded = r.decorations && !!r.decorations.faded; - const source = r.decorations && r.decorations.source || undefined; - const letter = r.decorations && r.decorations.letter || undefined; - const color = r.decorations && r.decorations.color || undefined; - - const rawResource = [handle, sourceUri, icons, tooltip, strikeThrough, faded, source, letter, color] as SCMRawResource; + const rawResource = [handle, sourceUri, icons, tooltip, strikeThrough, faded] as SCMRawResource; return { rawResource, handle }; }); diff --git a/src/vs/workbench/api/common/extHostStorage.ts b/src/vs/workbench/api/common/extHostStorage.ts index 8e6911e631..b1827092e8 100644 --- a/src/vs/workbench/api/common/extHostStorage.ts +++ b/src/vs/workbench/api/common/extHostStorage.ts @@ -16,7 +16,7 @@ export interface IStorageChangeEvent { export class ExtHostStorage implements ExtHostStorageShape { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; private _proxy: MainThreadStorageShape; diff --git a/src/vs/workbench/api/common/extHostStoragePaths.ts b/src/vs/workbench/api/common/extHostStoragePaths.ts index 5fea39d51d..2c7f596ac4 100644 --- a/src/vs/workbench/api/common/extHostStoragePaths.ts +++ b/src/vs/workbench/api/common/extHostStoragePaths.ts @@ -9,7 +9,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export const IExtensionStoragePaths = createDecorator('IExtensionStoragePaths'); export interface IExtensionStoragePaths { - _serviceBrand: any; + _serviceBrand: undefined; whenReady: Promise; workspaceValue(extension: IExtensionDescription): string | undefined; globalValue(extension: IExtensionDescription): string; diff --git a/src/vs/workbench/api/common/extHostTask.ts b/src/vs/workbench/api/common/extHostTask.ts index 0eb550f914..d0302877a0 100644 --- a/src/vs/workbench/api/common/extHostTask.ts +++ b/src/vs/workbench/api/common/extHostTask.ts @@ -12,7 +12,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export interface IExtHostTask extends ExtHostTaskShape { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; taskExecutions: vscode.TaskExecution[]; onDidStartTask: Event; diff --git a/src/vs/workbench/api/common/extHostTerminalService.ts b/src/vs/workbench/api/common/extHostTerminalService.ts index b436a5fe5f..40d279aa7a 100644 --- a/src/vs/workbench/api/common/extHostTerminalService.ts +++ b/src/vs/workbench/api/common/extHostTerminalService.ts @@ -4,14 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { Event } from 'vs/base/common/event'; -import { ExtHostTerminalServiceShape } from 'vs/workbench/api/common/extHost.protocol'; +import { Event, Emitter } from 'vs/base/common/event'; +import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { URI, UriComponents } from 'vs/base/common/uri'; +import { EXT_HOST_CREATION_DELAY, ITerminalChildProcess, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal'; +import { timeout } from 'vs/base/common/async'; +import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; export interface IExtHostTerminalService extends ExtHostTerminalServiceShape { - _serviceBrand: any; + _serviceBrand: undefined; activeTerminal: vscode.Terminal | undefined; terminals: vscode.Terminal[]; @@ -30,3 +34,562 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape { } export const IExtHostTerminalService = createDecorator('IExtHostTerminalService'); + +export class BaseExtHostTerminal { + public _id: number | undefined; + protected _idPromise: Promise; + private _idPromiseComplete: ((value: number) => any) | undefined; + private _disposed: boolean = false; + private _queuedRequests: ApiRequest[] = []; + + constructor( + protected _proxy: MainThreadTerminalServiceShape, + id?: number + ) { + this._idPromise = new Promise(c => { + if (id !== undefined) { + this._id = id; + c(id); + } else { + this._idPromiseComplete = c; + } + }); + } + + public dispose(): void { + if (!this._disposed) { + this._disposed = true; + this._queueApiRequest(this._proxy.$dispose, []); + } + } + + protected _checkDisposed() { + if (this._disposed) { + throw new Error('Terminal has already been disposed'); + } + } + + protected _queueApiRequest(callback: (...args: any[]) => void, args: any[]): void { + const request: ApiRequest = new ApiRequest(callback, args); + if (!this._id) { + this._queuedRequests.push(request); + return; + } + request.run(this._proxy, this._id); + } + + public _runQueuedRequests(id: number): void { + this._id = id; + if (this._idPromiseComplete) { + this._idPromiseComplete(id); + this._idPromiseComplete = undefined; + } + this._queuedRequests.forEach((r) => { + r.run(this._proxy, id); + }); + this._queuedRequests.length = 0; + } +} + +export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Terminal { + private _pidPromise: Promise; + private _cols: number | undefined; + private _pidPromiseComplete: ((value: number | undefined) => any) | undefined; + private _rows: number | undefined; + + public isOpen: boolean = false; + + constructor( + proxy: MainThreadTerminalServiceShape, + private _name?: string, + id?: number + ) { + super(proxy, id); + this._pidPromise = new Promise(c => this._pidPromiseComplete = c); + } + + public async create( + shellPath?: string, + shellArgs?: string[] | string, + cwd?: string | URI, + env?: { [key: string]: string | null }, + waitOnExit?: boolean, + strictEnv?: boolean, + hideFromUser?: boolean + ): 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 async createExtensionTerminal(): Promise { + const terminal = await this._proxy.$createTerminal({ name: this._name, isExtensionTerminal: true }); + this._name = terminal.name; + this._runQueuedRequests(terminal.id); + return terminal.id; + } + + public get name(): string { + return this._name || ''; + } + + public set name(name: string) { + this._name = name; + } + + public get dimensions(): vscode.TerminalDimensions | undefined { + if (this._cols === undefined || this._rows === undefined) { + return undefined; + } + return { + columns: this._cols, + rows: this._rows + }; + } + + public setDimensions(cols: number, rows: number): boolean { + if (cols === this._cols && rows === this._rows) { + // Nothing changed + return false; + } + this._cols = cols; + this._rows = rows; + return true; + } + + public get processId(): Promise { + return this._pidPromise; + } + + public sendText(text: string, addNewLine: boolean = true): void { + this._checkDisposed(); + this._queueApiRequest(this._proxy.$sendText, [text, addNewLine]); + } + + public show(preserveFocus: boolean): void { + this._checkDisposed(); + this._queueApiRequest(this._proxy.$show, [preserveFocus]); + } + + public hide(): void { + this._checkDisposed(); + this._queueApiRequest(this._proxy.$hide, []); + } + + public _setProcessId(processId: number | undefined): void { + // The event may fire 2 times when the panel is restored + if (this._pidPromiseComplete) { + this._pidPromiseComplete(processId); + this._pidPromiseComplete = undefined; + } else { + // Recreate the promise if this is the nth processId set (e.g. reused task terminals) + this._pidPromise.then(pid => { + if (pid !== processId) { + this._pidPromise = Promise.resolve(processId); + } + }); + } + } +} + +class ApiRequest { + private _callback: (...args: any[]) => void; + private _args: any[]; + + constructor(callback: (...args: any[]) => void, args: any[]) { + this._callback = callback; + this._args = args; + } + + public run(proxy: MainThreadTerminalServiceShape, id: number) { + this._callback.apply(proxy, [id].concat(this._args)); + } +} + +export class ExtHostPseudoterminal implements ITerminalChildProcess { + private readonly _onProcessData = new Emitter(); + public readonly onProcessData: Event = this._onProcessData.event; + private readonly _onProcessExit = new Emitter(); + public readonly onProcessExit: Event = this._onProcessExit.event; + private readonly _onProcessReady = new Emitter<{ pid: number, cwd: string }>(); + public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; } + private readonly _onProcessTitleChanged = new Emitter(); + public readonly onProcessTitleChanged: Event = this._onProcessTitleChanged.event; + private readonly _onProcessOverrideDimensions = new Emitter(); + public get onProcessOverrideDimensions(): Event { return this._onProcessOverrideDimensions.event; } + + constructor(private readonly _pty: vscode.Pseudoterminal) { } + + shutdown(): void { + this._pty.close(); + } + + input(data: string): void { + if (this._pty.handleInput) { + this._pty.handleInput(data); + } + } + + resize(cols: number, rows: number): void { + if (this._pty.setDimensions) { + this._pty.setDimensions({ columns: cols, rows }); + } + } + + getInitialCwd(): Promise { + return Promise.resolve(''); + } + + getCwd(): Promise { + return Promise.resolve(''); + } + + getLatency(): Promise { + return Promise.resolve(0); + } + + startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void { + // Attach the listeners + this._pty.onDidWrite(e => this._onProcessData.fire(e)); + if (this._pty.onDidClose) { + this._pty.onDidClose(e => this._onProcessExit.fire(e || 0)); + } + if (this._pty.onDidOverrideDimensions) { + this._pty.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : undefined)); // {{SQL CARBONEDIT}} strict-null-checks + } + + this._pty.open(initialDimensions ? initialDimensions : undefined); + } +} + +export abstract class BaseExtHostTerminalService implements IExtHostTerminalService, ExtHostTerminalServiceShape { + + readonly _serviceBrand: undefined; + + protected _proxy: MainThreadTerminalServiceShape; + protected _activeTerminal: ExtHostTerminal | undefined; + protected _terminals: ExtHostTerminal[] = []; + protected _terminalProcesses: { [id: number]: ITerminalChildProcess } = {}; + protected _getTerminalPromises: { [id: number]: Promise } = {}; + + public get activeTerminal(): ExtHostTerminal | undefined { return this._activeTerminal; } + public get terminals(): ExtHostTerminal[] { return this._terminals; } + + protected readonly _onDidCloseTerminal: Emitter = new Emitter(); + public get onDidCloseTerminal(): Event { return this._onDidCloseTerminal && this._onDidCloseTerminal.event; } + protected readonly _onDidOpenTerminal: Emitter = new Emitter(); + public get onDidOpenTerminal(): Event { return this._onDidOpenTerminal && this._onDidOpenTerminal.event; } + protected readonly _onDidChangeActiveTerminal: Emitter = new Emitter(); + public get onDidChangeActiveTerminal(): Event { return this._onDidChangeActiveTerminal && this._onDidChangeActiveTerminal.event; } + protected readonly _onDidChangeTerminalDimensions: Emitter = new Emitter(); + public get onDidChangeTerminalDimensions(): Event { return this._onDidChangeTerminalDimensions && this._onDidChangeTerminalDimensions.event; } + protected readonly _onDidWriteTerminalData: Emitter; + public get onDidWriteTerminalData(): Event { return this._onDidWriteTerminalData && this._onDidWriteTerminalData.event; } + + constructor( + @IExtHostRpcService extHostRpc: IExtHostRpcService + ) { + this._proxy = extHostRpc.getProxy(MainContext.MainThreadTerminalService); + this._onDidWriteTerminalData = new Emitter({ + onFirstListenerAdd: () => this._proxy.$startSendingDataEvents(), + onLastListenerRemove: () => this._proxy.$stopSendingDataEvents() + }); + } + + public abstract createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal; + public abstract createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal; + public abstract getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string; + public abstract $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise; + public abstract $requestAvailableShells(): Promise; + public abstract $requestDefaultShellAndArgs(useAutomationShell: boolean): Promise; + public abstract $acceptWorkspacePermissionsChanged(isAllowed: boolean): void; + + public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal { + const terminal = new ExtHostTerminal(this._proxy, options.name); + const p = new ExtHostPseudoterminal(options.pty); + terminal.createExtensionTerminal().then(id => this._setupExtHostProcessListeners(id, p)); + this._terminals.push(terminal); + return terminal; + } + + public attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void { + const terminal = this._getTerminalByIdEventually(id); + if (!terminal) { + throw new Error(`Cannot resolve terminal with id ${id} for virtual process`); + } + const p = new ExtHostPseudoterminal(pty); + this._setupExtHostProcessListeners(id, p); + } + + public async $acceptActiveTerminalChanged(id: number | null): Promise { + const original = this._activeTerminal; + if (id === null) { + this._activeTerminal = undefined; + if (original !== this._activeTerminal) { + this._onDidChangeActiveTerminal.fire(this._activeTerminal); + } + return; + } + const terminal = await this._getTerminalByIdEventually(id); + if (terminal) { + this._activeTerminal = terminal; + if (original !== this._activeTerminal) { + this._onDidChangeActiveTerminal.fire(this._activeTerminal); + } + } + } + + public async $acceptTerminalProcessData(id: number, data: string): Promise { + const terminal = await this._getTerminalByIdEventually(id); + if (terminal) { + this._onDidWriteTerminalData.fire({ terminal, data }); + } + } + + public async $acceptTerminalDimensions(id: number, cols: number, rows: number): Promise { + const terminal = await this._getTerminalByIdEventually(id); + if (terminal) { + if (terminal.setDimensions(cols, rows)) { + this._onDidChangeTerminalDimensions.fire({ + terminal: terminal, + dimensions: terminal.dimensions as vscode.TerminalDimensions + }); + } + } + } + + public async $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): Promise { + await this._getTerminalByIdEventually(id); + + if (this._terminalProcesses[id]) { + // Extension pty terminal only - when virtual process resize fires it means that the + // terminal's maximum dimensions changed + this._terminalProcesses[id].resize(cols, rows); + } + } + + public async $acceptTerminalTitleChange(id: number, name: string): Promise { + await this._getTerminalByIdEventually(id); + const extHostTerminal = this._getTerminalObjectById(this.terminals, id); + if (extHostTerminal) { + extHostTerminal.name = name; + } + } + + public async $acceptTerminalClosed(id: number): Promise { + await this._getTerminalByIdEventually(id); + const index = this._getTerminalObjectIndexById(this.terminals, id); + if (index !== null) { + const terminal = this._terminals.splice(index, 1)[0]; + this._onDidCloseTerminal.fire(terminal); + } + } + + public $acceptTerminalOpened(id: number, name: string): void { + const index = this._getTerminalObjectIndexById(this._terminals, id); + if (index !== null) { + // The terminal has already been created (via createTerminal*), only fire the event + this._onDidOpenTerminal.fire(this.terminals[index]); + this.terminals[index].isOpen = true; + return; + } + + const terminal = new ExtHostTerminal(this._proxy, name, id); + this._terminals.push(terminal); + this._onDidOpenTerminal.fire(terminal); + terminal.isOpen = true; + } + + public async $acceptTerminalProcessId(id: number, processId: number): Promise { + const terminal = await this._getTerminalByIdEventually(id); + if (terminal) { + terminal._setProcessId(processId); + } + } + + public performTerminalIdAction(id: number, callback: (terminal: ExtHostTerminal) => void): void { + // TODO: Use await this._getTerminalByIdEventually(id); + let terminal = this._getTerminalById(id); + if (terminal) { + callback(terminal); + } else { + // Retry one more time in case the terminal has not yet been initialized. + setTimeout(() => { + terminal = this._getTerminalById(id); + if (terminal) { + callback(terminal); + } + }, EXT_HOST_CREATION_DELAY * 2); + } + } + + public async $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise { + // Make sure the ExtHostTerminal exists so onDidOpenTerminal has fired before we call + // Pseudoterminal.start + const terminal = await this._getTerminalByIdEventually(id); + if (!terminal) { + return; + } + + // Wait for onDidOpenTerminal to fire + let openPromise: Promise; + if (terminal.isOpen) { + openPromise = Promise.resolve(); + } else { + openPromise = new Promise(r => { + // Ensure open is called after onDidOpenTerminal + const listener = this.onDidOpenTerminal(async e => { + if (e === terminal) { + listener.dispose(); + r(); + } + }); + }); + } + await openPromise; + + // 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); + } + } + + protected _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): void { + p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd)); + p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title)); + p.onProcessData(data => this._proxy.$sendProcessData(id, data)); + p.onProcessExit(exitCode => this._onProcessExit(id, exitCode)); + if (p.onProcessOverrideDimensions) { + p.onProcessOverrideDimensions(e => this._proxy.$sendOverrideDimensions(id, e)); + } + this._terminalProcesses[id] = p; + } + + public $acceptProcessInput(id: number, data: string): void { + this._terminalProcesses[id].input(data); + } + + public $acceptProcessResize(id: number, cols: number, rows: number): void { + try { + this._terminalProcesses[id].resize(cols, rows); + } catch (error) { + // We tried to write to a closed pipe / channel. + if (error.code !== 'EPIPE' && error.code !== 'ERR_IPC_CHANNEL_CLOSED') { + throw (error); + } + } + } + + public $acceptProcessShutdown(id: number, immediate: boolean): void { + this._terminalProcesses[id].shutdown(immediate); + } + + public $acceptProcessRequestInitialCwd(id: number): void { + this._terminalProcesses[id].getInitialCwd().then(initialCwd => this._proxy.$sendProcessInitialCwd(id, initialCwd)); + } + + public $acceptProcessRequestCwd(id: number): void { + this._terminalProcesses[id].getCwd().then(cwd => this._proxy.$sendProcessCwd(id, cwd)); + } + + public $acceptProcessRequestLatency(id: number): number { + return id; + } + + private _onProcessExit(id: number, exitCode: number): void { + // Remove process reference + delete this._terminalProcesses[id]; + + // Send exit event to main side + this._proxy.$sendProcessExit(id, exitCode); + } + + // TODO: This could be improved by using a single promise and resolve it when the terminal is ready + private _getTerminalByIdEventually(id: number, retries: number = 5): Promise { + if (!this._getTerminalPromises[id]) { + this._getTerminalPromises[id] = this._createGetTerminalPromise(id, retries); + } else { + this._getTerminalPromises[id].then(c => { + return this._createGetTerminalPromise(id, retries); + }); + } + return this._getTerminalPromises[id]; + } + + private _createGetTerminalPromise(id: number, retries: number = 5): Promise { + return new Promise(c => { + if (retries === 0) { + c(undefined); + return; + } + + const terminal = this._getTerminalById(id); + if (terminal) { + c(terminal); + } else { + // This should only be needed immediately after createTerminalRenderer is called as + // the ExtHostTerminal has not yet been iniitalized + timeout(200).then(() => c(this._createGetTerminalPromise(id, retries - 1))); + } + }); + } + + private _getTerminalById(id: number): ExtHostTerminal | null { + return this._getTerminalObjectById(this._terminals, id); + } + + private _getTerminalObjectById(array: T[], id: number): T | null { + const index = this._getTerminalObjectIndexById(array, id); + return index !== null ? array[index] : null; + } + + private _getTerminalObjectIndexById(array: T[], id: number): number | null { + let index: number | null = null; + array.some((item, i) => { + const thisId = item._id; + if (thisId === id) { + index = i; + return true; + } + return false; + }); + return index; + } +} + +export class WorkerExtHostTerminalService extends BaseExtHostTerminalService { + public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { + throw new Error('Not implemented'); + } + + public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal { + throw new Error('Not implemented'); + } + + public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string { + throw new Error('Not implemented'); + } + + public $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise { + throw new Error('Not implemented'); + } + + public $requestAvailableShells(): Promise { + throw new Error('Not implemented'); + } + + public async $requestDefaultShellAndArgs(useAutomationShell: boolean): Promise { + throw new Error('Not implemented'); + } + + public $acceptWorkspacePermissionsChanged(isAllowed: boolean): void { + // No-op for web worker ext host as workspace permissions aren't used + } +} diff --git a/src/vs/workbench/api/common/extHostTreeViews.ts b/src/vs/workbench/api/common/extHostTreeViews.ts index dcff183259..3b92133a9c 100644 --- a/src/vs/workbench/api/common/extHostTreeViews.ts +++ b/src/vs/workbench/api/common/extHostTreeViews.ts @@ -99,6 +99,11 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { checkProposedApiEnabled(extension); treeView.message = message; }, + get title() { return treeView.title; }, + set title(title: string) { + checkProposedApiEnabled(extension); + treeView.title = title; + }, reveal: (element: T, options?: IRevealOptions): Promise => { return treeView.reveal(element, options); }, @@ -200,6 +205,15 @@ export class ExtHostTreeView extends Disposable { constructor(private viewId: string, options: vscode.TreeViewOptions, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter, private logService: ILogService, private extension: IExtensionDescription) { super(); + if (extension.contributes && extension.contributes.views) { + for (const location in extension.contributes.views) { + for (const view of extension.contributes.views[location]) { + if (view.id === viewId) { + this._title = view.name; + } + } + } + } this.dataProvider = options.treeDataProvider; // {{SQL CARBON EDIT}} if (this.proxy) { @@ -282,6 +296,16 @@ export class ExtHostTreeView extends Disposable { this._onDidChangeData.fire({ message: true, element: false }); } + private _title: string = ''; + get title(): string { + return this._title; + } + + set title(title: string) { + this._title = title; + this.proxy.$setTitle(this.viewId, title); + } + setExpanded(treeItemHandle: TreeItemHandle, expanded: boolean): void { const element = this.getExtensionElement(treeItemHandle); if (element) { diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index ae3ab219eb..9327ff409c 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -19,7 +19,7 @@ import { IRange } from 'vs/editor/common/core/range'; import { ISelection } from 'vs/editor/common/core/selection'; import * as htmlContent from 'vs/base/common/htmlContent'; import * as languageSelector from 'vs/editor/common/modes/languageSelector'; -import { IWorkspaceEditDto, IResourceTextEditDto, IResourceFileEditDto } from 'vs/workbench/api/common/extHost.protocol'; +import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol'; import { MarkerSeverity, IRelatedInformation, IMarkerData, MarkerTag } from 'vs/platform/markers/common/markers'; import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; @@ -31,6 +31,7 @@ import { LogLevel as _MainLogLevel } from 'vs/platform/log/common/log'; import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays'; import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions'; + export interface PositionLike { line: number; character: number; @@ -473,8 +474,8 @@ export namespace TextEdit { } export namespace WorkspaceEdit { - export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors): IWorkspaceEditDto { - const result: IWorkspaceEditDto = { + export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors): extHostProtocol.IWorkspaceEditDto { + const result: extHostProtocol.IWorkspaceEditDto = { edits: [] }; for (const entry of (value as types.WorkspaceEdit)._allEntries()) { @@ -482,28 +483,28 @@ export namespace WorkspaceEdit { if (Array.isArray(uriOrEdits)) { // text edits const doc = documents && uri ? documents.getDocument(uri) : undefined; - result.edits.push({ resource: uri, modelVersionId: doc && doc.version, edits: uriOrEdits.map(TextEdit.from) }); + result.edits.push({ resource: uri, modelVersionId: doc && doc.version, edits: uriOrEdits.map(TextEdit.from) }); } else { // resource edits - result.edits.push({ oldUri: uri, newUri: uriOrEdits, options: entry[2] }); + result.edits.push({ oldUri: uri, newUri: uriOrEdits, options: entry[2] }); } } return result; } - export function to(value: IWorkspaceEditDto) { + export function to(value: extHostProtocol.IWorkspaceEditDto) { const result = new types.WorkspaceEdit(); for (const edit of value.edits) { - if (Array.isArray((edit).edits)) { + if (Array.isArray((edit).edits)) { result.set( - URI.revive((edit).resource), - (edit).edits.map(TextEdit.to) + URI.revive((edit).resource), + (edit).edits.map(TextEdit.to) ); } else { result.renameFile( - URI.revive((edit).oldUri!), - URI.revive((edit).newUri!), - (edit).options + URI.revive((edit).oldUri!), + URI.revive((edit).newUri!), + (edit).options ); } } @@ -626,6 +627,32 @@ export namespace DocumentSymbol { } } +export namespace CallHierarchyItem { + + export function from(item: vscode.CallHierarchyItem): extHostProtocol.ICallHierarchyItemDto { + return { + name: item.name, + detail: item.detail, + kind: SymbolKind.from(item.kind), + uri: item.uri, + range: Range.from(item.range), + selectionRange: Range.from(item.selectionRange), + }; + } + + export function to(item: extHostProtocol.ICallHierarchyItemDto): vscode.CallHierarchyItem { + return new types.CallHierarchyItem( + SymbolKind.to(item.kind), + item.name, + item.detail || '', + URI.revive(item.uri), + Range.to(item.range), + Range.to(item.selectionRange) + ); + } +} + + export namespace location { export function from(value: vscode.Location): modes.Location { return { @@ -1136,3 +1163,13 @@ export namespace LogLevel { return types.LogLevel.Info; } } +export namespace WebviewEditorState { + export function from(state: vscode.WebviewEditorState): modes.WebviewEditorState { + switch (state) { + case types.WebviewEditorState.Readonly: return modes.WebviewEditorState.Readonly; + case types.WebviewEditorState.Unchanged: return modes.WebviewEditorState.Unchanged; + case types.WebviewEditorState.Dirty: return modes.WebviewEditorState.Dirty; + default: throw new Error('Unknown vscode.WebviewEditorState'); + } + } +} diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 40530aa1fe..a05b4c48c6 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -1146,12 +1146,6 @@ export class SelectionRange { } } - -export enum CallHierarchyDirection { - CallsFrom = 1, - CallsTo = 2, -} - export class CallHierarchyItem { kind: SymbolKind; name: string; @@ -1170,6 +1164,27 @@ export class CallHierarchyItem { } } +export class CallHierarchyIncomingCall { + + source: vscode.CallHierarchyItem; + sourceRanges: vscode.Range[]; + + constructor(item: vscode.CallHierarchyItem, sourceRanges: vscode.Range[]) { + this.sourceRanges = sourceRanges; + this.source = item; + } +} +export class CallHierarchyOutgoingCall { + + target: vscode.CallHierarchyItem; + sourceRanges: vscode.Range[]; + + constructor(item: vscode.CallHierarchyItem, sourceRanges: vscode.Range[]) { + this.sourceRanges = sourceRanges; + this.target = item; + } +} + @es5ClassCompat export class CodeLens { @@ -2345,12 +2360,31 @@ export class QuickInputButtons { private constructor() { } } -export enum ExtensionExecutionContext { - Local = 1, - Remote = 2 -} - export enum ExtensionKind { UI = 1, Workspace = 2 } + +export class Decoration { + + static validate(d: Decoration): void { + if (d.letter && d.letter.length !== 1) { + throw new Error(`The 'letter'-property must be undefined or a single character`); + } + if (!d.bubble && !d.color && !d.letter && !d.priority && !d.title) { + throw new Error(`The decoration is empty`); + } + } + + letter?: string; + title?: string; + color?: vscode.ThemeColor; + priority?: number; + bubble?: boolean; +} + +export enum WebviewEditorState { + Readonly = 1, + Unchanged = 2, + Dirty = 3, +} diff --git a/src/vs/workbench/api/common/extHostUriTransformerService.ts b/src/vs/workbench/api/common/extHostUriTransformerService.ts index 1810ded74a..f5a19a9f85 100644 --- a/src/vs/workbench/api/common/extHostUriTransformerService.ts +++ b/src/vs/workbench/api/common/extHostUriTransformerService.ts @@ -8,13 +8,13 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { URI, UriComponents } from 'vs/base/common/uri'; export interface IURITransformerService extends IURITransformer { - _serviceBrand: any; + _serviceBrand: undefined; } export const IURITransformerService = createDecorator('IURITransformerService'); export class URITransformerService implements IURITransformerService { - _serviceBrand: any; + _serviceBrand: undefined; transformIncoming: (uri: UriComponents) => UriComponents; transformOutgoing: (uri: UriComponents) => UriComponents; diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index c69754526d..e9a66e62a9 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { URI } from 'vs/base/common/uri'; +import { URI, UriComponents } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import * as modes from 'vs/editor/common/modes'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; @@ -13,7 +13,7 @@ import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview'; import * as vscode from 'vscode'; import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewStateData } from './extHost.protocol'; -import { Disposable } from './extHostTypes'; +import { Disposable, WebviewEditorState } from './extHostTypes'; type IconPath = URI | { light: URI, dark: URI }; @@ -40,7 +40,9 @@ export class ExtHostWebview implements vscode.Webview { } public get cspSource(): string { - return this._initData.webviewCspSource.replace('{{uuid}}', this._handle); + return this._initData.webviewCspSource + .replace('{{uuid}}', this._handle) + .replace('{{commit}}', this._initData.commit || '211fa02efe8c041fd7baa8ec3dce199d5185aa44'); } public get html(): string { @@ -79,7 +81,7 @@ export class ExtHostWebview implements vscode.Webview { } } -export class ExtHostWebviewPanel implements vscode.WebviewPanel { +export class ExtHostWebviewEditor implements vscode.WebviewEditor { private readonly _handle: WebviewPanelHandle; private readonly _proxy: MainThreadWebviewsShape; @@ -92,6 +94,7 @@ export class ExtHostWebviewPanel implements vscode.WebviewPanel { private _viewColumn: vscode.ViewColumn | undefined; private _visible: boolean = true; private _active: boolean = true; + private _state = WebviewEditorState.Readonly; _isDisposed: boolean = false; @@ -212,6 +215,15 @@ export class ExtHostWebviewPanel implements vscode.WebviewPanel { this._visible = value; } + public get state(): vscode.WebviewEditorState { + return this._state; + } + + public set state(newState: vscode.WebviewEditorState) { + this._state = newState; + this._proxy.$setState(this._handle, typeConverters.WebviewEditorState.from(newState)); + } + public postMessage(message: any): Promise { this.assertNotDisposed(); return this._proxy.$postMessage(this._handle, message); @@ -239,8 +251,9 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { } private readonly _proxy: MainThreadWebviewsShape; - private readonly _webviewPanels = new Map(); + private readonly _webviewPanels = new Map(); private readonly _serializers = new Map(); + private readonly _editorProviders = new Map(); constructor( mainContext: IMainContext, @@ -266,7 +279,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { this._proxy.$createWebviewPanel(handle, viewType, title, webviewShowOptions, convertWebviewOptions(options), extension.identifier, extension.extensionLocation); const webview = new ExtHostWebview(handle, this._proxy, options, this.initData); - const panel = new ExtHostWebviewPanel(handle, this._proxy, viewType, title, viewColumn, options, webview); + const panel = new ExtHostWebviewEditor(handle, this._proxy, viewType, title, viewColumn, options, webview); this._webviewPanels.set(handle, panel); return panel; } @@ -288,6 +301,23 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { }); } + public registerWebviewEditorProvider( + viewType: string, + provider: vscode.WebviewEditorProvider + ): vscode.Disposable { + if (this._editorProviders.has(viewType)) { + throw new Error(`Editor provider for '${viewType}' already registered`); + } + + this._editorProviders.set(viewType, provider); + this._proxy.$registerEditorProvider(viewType); + + return new Disposable(() => { + this._editorProviders.delete(viewType); + this._proxy.$unregisterEditorProvider(viewType); + }); + } + public $onMessage( handle: WebviewPanelHandle, message: any @@ -298,6 +328,13 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { } } + public $onMissingCsp( + _handle: WebviewPanelHandle, + extensionId: string + ): void { + console.warn(`${extensionId} created a webview without a content security policy: https://aka.ms/vscode-webview-missing-csp`); + } + public $onDidChangeWebviewPanelViewStates(newStates: WebviewPanelViewStateData): void { const handles = Object.keys(newStates); // Notify webviews of state changes in the following order: @@ -356,14 +393,35 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { } const webview = new ExtHostWebview(webviewHandle, this._proxy, options, this.initData); - const revivedPanel = new ExtHostWebviewPanel(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview); + const revivedPanel = new ExtHostWebviewEditor(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview); this._webviewPanels.set(webviewHandle, revivedPanel); return Promise.resolve(serializer.deserializeWebviewPanel(revivedPanel, state)); } - private getWebviewPanel(handle: WebviewPanelHandle): ExtHostWebviewPanel | undefined { + private getWebviewPanel(handle: WebviewPanelHandle): ExtHostWebviewEditor | undefined { return this._webviewPanels.get(handle); } + + async $resolveWebviewEditor( + resource: UriComponents, + webviewHandle: WebviewPanelHandle, + viewType: string, + title: string, + state: any, + position: EditorViewColumn, + options: modes.IWebviewOptions & modes.IWebviewPanelOptions + ): Promise { + const provider = this._editorProviders.get(viewType); + if (!provider) { + return Promise.reject(new Error(`No provider found for '${viewType}'`)); + } + + const webview = new ExtHostWebview(webviewHandle, this._proxy, options, this.initData); + const revivedPanel = new ExtHostWebviewEditor(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview); + this._webviewPanels.set(webviewHandle, revivedPanel); + return Promise.resolve(provider.resolveWebviewEditor(URI.revive(resource), revivedPanel)); + } + } function convertWebviewOptions( diff --git a/src/vs/workbench/api/common/extHostWorkspace.ts b/src/vs/workbench/api/common/extHostWorkspace.ts index b928faaf29..227891e6e7 100644 --- a/src/vs/workbench/api/common/extHostWorkspace.ts +++ b/src/vs/workbench/api/common/extHostWorkspace.ts @@ -156,7 +156,7 @@ class ExtHostWorkspaceImpl extends Workspace { export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspaceProvider { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; private readonly _onDidChangeWorkspace = new Emitter(); readonly onDidChangeWorkspace: Event = this._onDidChangeWorkspace.event; diff --git a/src/vs/workbench/api/common/shared/webview.ts b/src/vs/workbench/api/common/shared/webview.ts index cd73dfe51a..4f61c3c04a 100644 --- a/src/vs/workbench/api/common/shared/webview.ts +++ b/src/vs/workbench/api/common/shared/webview.ts @@ -7,6 +7,7 @@ import { URI } from 'vs/base/common/uri'; import * as vscode from 'vscode'; export interface WebviewInitData { + readonly commit?: string; readonly webviewResourceRoot: string; readonly webviewCspSource: string; } @@ -14,11 +15,11 @@ export interface WebviewInitData { export function asWebviewUri( initData: WebviewInitData, uuid: string, - resource: vscode.Uri + resource: vscode.Uri, ): vscode.Uri { const uri = initData.webviewResourceRoot + .replace('{{commit}}', initData.commit || '211fa02efe8c041fd7baa8ec3dce199d5185aa44') .replace('{{resource}}', resource.toString().replace(/^\S+?:/, '')) .replace('{{uuid}}', uuid); - return URI.parse(uri); } diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index bbf3c7529b..217d2926f1 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -41,7 +41,7 @@ import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugServic export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugServiceShape { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; private _configProviderHandleCounter: number; private _configProviders: ConfigProviderTuple[]; @@ -687,6 +687,13 @@ export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugSe this._onDidChangeActiveDebugSession.fire(this._activeDebugSession); } + public async $acceptDebugSessionNameChanged(sessionDto: IDebugSessionDto, name: string): Promise { + const session = await this.getSession(sessionDto); + if (session) { + session._acceptNameChanged(name); + } + } + public async $acceptDebugSessionCustomEvent(sessionDto: IDebugSessionDto, event: any): Promise { const session = await this.getSession(sessionDto); const ee: vscode.DebugSessionCustomEvent = { @@ -917,6 +924,15 @@ export class ExtHostDebugSession implements vscode.DebugSession { return this._name; } + public set name(name: string) { + this._name = name; + this._debugServiceProxy.$setDebugSessionName(this._id, name); + } + + _acceptNameChanged(name: string) { + this._name = name; + } + public get workspaceFolder(): vscode.WorkspaceFolder | undefined { return this._workspaceFolder; } diff --git a/src/vs/workbench/api/node/extHostOutputService.ts b/src/vs/workbench/api/node/extHostOutputService.ts index 6650d84a66..7a5e4ccecb 100644 --- a/src/vs/workbench/api/node/extHostOutputService.ts +++ b/src/vs/workbench/api/node/extHostOutputService.ts @@ -13,6 +13,7 @@ import { dirExists, mkdirp } from 'vs/base/node/pfs'; import { AbstractExtHostOutputChannel, ExtHostPushOutputChannel, ExtHostOutputService, LazyOutputChannel } from 'vs/workbench/api/common/extHostOutput'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; +import { MutableDisposable } from 'vs/base/common/lifecycle'; export class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChannel { @@ -49,6 +50,8 @@ export class ExtHostOutputService2 extends ExtHostOutputService { private _logsLocation: URI; private _namePool: number = 1; + private readonly _channels: Map = new Map(); + private readonly _visibleChannelDisposable = new MutableDisposable(); constructor( @IExtHostRpcService extHostRpc: IExtHostRpcService, @@ -58,12 +61,23 @@ export class ExtHostOutputService2 extends ExtHostOutputService { this._logsLocation = initData.logsLocation; } + $setVisibleChannel(channelId: string): void { + if (channelId) { + const channel = this._channels.get(channelId); + if (channel) { + this._visibleChannelDisposable.value = channel.onDidAppend(() => channel.update()); + } + } + } + createOutputChannel(name: string): vscode.OutputChannel { name = name.trim(); if (!name) { throw new Error('illegal argument `name`. must not be falsy'); } - return new LazyOutputChannel(name, this._doCreateOutChannel(name)); + const extHostOutputChannel = this._doCreateOutChannel(name); + extHostOutputChannel.then(channel => channel._id.then(id => this._channels.set(id, channel))); + return new LazyOutputChannel(name, extHostOutputChannel); } private async _doCreateOutChannel(name: string): Promise { diff --git a/src/vs/workbench/api/node/extHostSearch.ts b/src/vs/workbench/api/node/extHostSearch.ts index d3baf488aa..94a5194023 100644 --- a/src/vs/workbench/api/node/extHostSearch.ts +++ b/src/vs/workbench/api/node/extHostSearch.ts @@ -29,8 +29,8 @@ export class ExtHostSearch implements ExtHostSearchShape { private readonly _fileSearchUsedSchemes = new Set(); private _handlePool: number = 0; - private _internalFileSearchHandle: number; - private _internalFileSearchProvider: SearchService | null; + private _internalFileSearchHandle: number = -1; + private _internalFileSearchProvider: SearchService | null = null; private _fileSearchManager: FileSearchManager; diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index 410cb06627..3c327050ba 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -357,7 +357,7 @@ interface HandlerData { export class ExtHostTask implements ExtHostTaskShape { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; private readonly _proxy: MainThreadTaskShape; private readonly _workspaceProvider: IExtHostWorkspaceProvider; @@ -662,6 +662,10 @@ export class ExtHostTask implements ExtHostTaskShape { return undefined; } + public $getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }> { + return this._terminalService.$requestDefaultShellAndArgs(true); + } + private nextHandle(): number { return this._handleCounter++; } diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index 8fb99a7f8c..7c0ac35128 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -9,223 +9,28 @@ import * as os from 'os'; import { URI, UriComponents } from 'vs/base/common/uri'; import * as platform from 'vs/base/common/platform'; import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -import { Event, Emitter } from 'vs/base/common/event'; -import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol'; +import { IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostConfiguration, ExtHostConfigProvider, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration'; import { ILogService } from 'vs/platform/log/common/log'; -import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig, ITerminalEnvironment, ITerminalChildProcess, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IShellLaunchConfig, ITerminalEnvironment } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess'; -import { timeout } from 'vs/base/common/async'; import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { ExtHostVariableResolverService } from 'vs/workbench/api/node/extHostDebugService'; import { ExtHostDocumentsAndEditors, IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; import { getSystemShell, detectAvailableShells } from 'vs/workbench/contrib/terminal/node/terminal'; import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment'; -import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService'; +import { BaseExtHostTerminalService, ExtHostTerminal } from 'vs/workbench/api/common/extHostTerminalService'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; -export class BaseExtHostTerminal { - public _id: number | undefined; - protected _idPromise: Promise; - private _idPromiseComplete: ((value: number) => any) | undefined; - private _disposed: boolean = false; - private _queuedRequests: ApiRequest[] = []; +export class ExtHostTerminalService extends BaseExtHostTerminalService { - constructor( - protected _proxy: MainThreadTerminalServiceShape, - id?: number - ) { - this._idPromise = new Promise(c => { - if (id !== undefined) { - this._id = id; - c(id); - } else { - this._idPromiseComplete = c; - } - }); - } - - public dispose(): void { - if (!this._disposed) { - this._disposed = true; - this._queueApiRequest(this._proxy.$dispose, []); - } - } - - protected _checkDisposed() { - if (this._disposed) { - throw new Error('Terminal has already been disposed'); - } - } - - protected _queueApiRequest(callback: (...args: any[]) => void, args: any[]): void { - const request: ApiRequest = new ApiRequest(callback, args); - if (!this._id) { - this._queuedRequests.push(request); - return; - } - request.run(this._proxy, this._id); - } - - public _runQueuedRequests(id: number): void { - this._id = id; - if (this._idPromiseComplete) { - this._idPromiseComplete(id); - this._idPromiseComplete = undefined; - } - this._queuedRequests.forEach((r) => { - r.run(this._proxy, id); - }); - this._queuedRequests.length = 0; - } -} - -export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Terminal { - private _pidPromise: Promise; - private _cols: number | undefined; - private _pidPromiseComplete: ((value: number | undefined) => any) | undefined; - private _rows: number | undefined; - - /** @deprecated */ - private readonly _onData = new Emitter(); - /** @deprecated */ - public get onDidWriteData(): Event { - // Tell the main side to start sending data if it's not already - this._idPromise.then(id => { - this._proxy.$registerOnDataListener(id); - }); - return this._onData.event; - } - - public isOpen: boolean = false; - - constructor( - proxy: MainThreadTerminalServiceShape, - private _name?: string, - id?: number - ) { - super(proxy, id); - this._pidPromise = new Promise(c => this._pidPromiseComplete = c); - } - - public async create( - shellPath?: string, - shellArgs?: string[] | string, - cwd?: string | URI, - env?: { [key: string]: string | null }, - waitOnExit?: boolean, - strictEnv?: boolean, - hideFromUser?: boolean - ): 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 async createExtensionTerminal(): Promise { - const terminal = await this._proxy.$createTerminal({ name: this._name, isExtensionTerminal: true }); - this._name = terminal.name; - this._runQueuedRequests(terminal.id); - return terminal.id; - } - - public get name(): string { - return this._name || ''; - } - - public set name(name: string) { - this._name = name; - } - - public get dimensions(): vscode.TerminalDimensions | undefined { - if (this._cols === undefined || this._rows === undefined) { - return undefined; - } - return { - columns: this._cols, - rows: this._rows - }; - } - - public setDimensions(cols: number, rows: number): boolean { - if (cols === this._cols && rows === this._rows) { - // Nothing changed - return false; - } - this._cols = cols; - this._rows = rows; - return true; - } - - public get processId(): Promise { - return this._pidPromise; - } - - public sendText(text: string, addNewLine: boolean = true): void { - this._checkDisposed(); - this._queueApiRequest(this._proxy.$sendText, [text, addNewLine]); - } - - public show(preserveFocus: boolean): void { - this._checkDisposed(); - this._queueApiRequest(this._proxy.$show, [preserveFocus]); - } - - public hide(): void { - this._checkDisposed(); - this._queueApiRequest(this._proxy.$hide, []); - } - - public _setProcessId(processId: number | undefined): void { - // The event may fire 2 times when the panel is restored - if (this._pidPromiseComplete) { - this._pidPromiseComplete(processId); - this._pidPromiseComplete = undefined; - } else { - // Recreate the promise if this is the nth processId set (e.g. reused task terminals) - this._pidPromise.then(pid => { - if (pid !== processId) { - this._pidPromise = Promise.resolve(processId); - } - }); - } - } - - public _fireOnData(data: string): void { - this._onData.fire(data); - } -} - -export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostTerminalServiceShape { - - readonly _serviceBrand: any; - - private _proxy: MainThreadTerminalServiceShape; - private _activeTerminal: ExtHostTerminal | undefined; - private _terminals: ExtHostTerminal[] = []; - private _terminalProcesses: { [id: number]: ITerminalChildProcess } = {}; - private _getTerminalPromises: { [id: number]: Promise } = {}; private _variableResolver: ExtHostVariableResolverService | undefined; private _lastActiveWorkspace: IWorkspaceFolder | undefined; // TODO: Pull this from main side private _isWorkspaceShellAllowed: boolean = false; - public get activeTerminal(): ExtHostTerminal | undefined { return this._activeTerminal; } - public get terminals(): ExtHostTerminal[] { return this._terminals; } - - private readonly _onDidCloseTerminal: Emitter = new Emitter(); - public get onDidCloseTerminal(): Event { return this._onDidCloseTerminal && this._onDidCloseTerminal.event; } - private readonly _onDidOpenTerminal: Emitter = new Emitter(); - public get onDidOpenTerminal(): Event { return this._onDidOpenTerminal && this._onDidOpenTerminal.event; } - private readonly _onDidChangeActiveTerminal: Emitter = new Emitter(); - public get onDidChangeActiveTerminal(): Event { return this._onDidChangeActiveTerminal && this._onDidChangeActiveTerminal.event; } - private readonly _onDidChangeTerminalDimensions: Emitter = new Emitter(); - public get onDidChangeTerminalDimensions(): Event { return this._onDidChangeTerminalDimensions && this._onDidChangeTerminalDimensions.event; } - private readonly _onDidWriteTerminalData: Emitter; - public get onDidWriteTerminalData(): Event { return this._onDidWriteTerminalData && this._onDidWriteTerminalData.event; } - constructor( @IExtHostRpcService extHostRpc: IExtHostRpcService, @IExtHostConfiguration private _extHostConfiguration: ExtHostConfiguration, @@ -233,11 +38,7 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT @IExtHostDocumentsAndEditors private _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors, @ILogService private _logService: ILogService ) { - this._proxy = extHostRpc.getProxy(MainContext.MainThreadTerminalService); - this._onDidWriteTerminalData = new Emitter({ - onFirstListenerAdd: () => this._proxy.$startSendingDataEvents(), - onLastListenerRemove: () => this._proxy.$stopSendingDataEvents() - }); + super(extHostRpc); this._updateLastActiveWorkspace(); this._updateVariableResolver(); this._registerListeners(); @@ -257,23 +58,6 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT return terminal; } - public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal { - const terminal = new ExtHostTerminal(this._proxy, options.name); - const p = new ExtHostPseudoterminal(options.pty); - terminal.createExtensionTerminal().then(id => this._setupExtHostProcessListeners(id, p)); - this._terminals.push(terminal); - return terminal; - } - - public attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void { - const terminal = this._getTerminalByIdEventually(id); - if (!terminal) { - throw new Error(`Cannot resolve terminal with id ${id} for virtual process`); - } - const p = new ExtHostPseudoterminal(pty); - this._setupExtHostProcessListeners(id, p); - } - public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string { const fetchSetting = (key: string) => { const setting = configProvider @@ -305,116 +89,6 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT return terminalEnvironment.getDefaultShellArgs(fetchSetting, this._isWorkspaceShellAllowed, useAutomationShell, this._lastActiveWorkspace, this._variableResolver, this._logService); } - public async $acceptActiveTerminalChanged(id: number | null): Promise { - const original = this._activeTerminal; - if (id === null) { - this._activeTerminal = undefined; - if (original !== this._activeTerminal) { - this._onDidChangeActiveTerminal.fire(this._activeTerminal); - } - return; - } - const terminal = await this._getTerminalByIdEventually(id); - if (terminal) { - this._activeTerminal = terminal; - if (original !== this._activeTerminal) { - this._onDidChangeActiveTerminal.fire(this._activeTerminal); - } - } - } - - /** @deprecated */ - public async $acceptTerminalProcessData(id: number, data: string): Promise { - const terminal = await this._getTerminalByIdEventually(id); - if (terminal) { - terminal._fireOnData(data); - } - } - - public async $acceptTerminalProcessData2(id: number, data: string): Promise { - const terminal = await this._getTerminalByIdEventually(id); - if (terminal) { - this._onDidWriteTerminalData.fire({ terminal, data }); - } - } - - public async $acceptTerminalDimensions(id: number, cols: number, rows: number): Promise { - const terminal = await this._getTerminalByIdEventually(id); - if (terminal) { - if (terminal.setDimensions(cols, rows)) { - this._onDidChangeTerminalDimensions.fire({ - terminal: terminal, - dimensions: terminal.dimensions as vscode.TerminalDimensions - }); - } - } - } - - public async $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): Promise { - await this._getTerminalByIdEventually(id); - - if (this._terminalProcesses[id]) { - // Extension pty terminal only - when virtual process resize fires it means that the - // terminal's maximum dimensions changed - this._terminalProcesses[id].resize(cols, rows); - } - } - - public async $acceptTerminalTitleChange(id: number, name: string): Promise { - await this._getTerminalByIdEventually(id); - const extHostTerminal = this._getTerminalObjectById(this.terminals, id); - if (extHostTerminal) { - extHostTerminal.name = name; - } - } - - public async $acceptTerminalClosed(id: number): Promise { - await this._getTerminalByIdEventually(id); - const index = this._getTerminalObjectIndexById(this.terminals, id); - if (index !== null) { - const terminal = this._terminals.splice(index, 1)[0]; - this._onDidCloseTerminal.fire(terminal); - } - } - - public $acceptTerminalOpened(id: number, name: string): void { - const index = this._getTerminalObjectIndexById(this._terminals, id); - if (index !== null) { - // The terminal has already been created (via createTerminal*), only fire the event - this._onDidOpenTerminal.fire(this.terminals[index]); - this.terminals[index].isOpen = true; - return; - } - - const terminal = new ExtHostTerminal(this._proxy, name, id); - this._terminals.push(terminal); - this._onDidOpenTerminal.fire(terminal); - terminal.isOpen = true; - } - - public async $acceptTerminalProcessId(id: number, processId: number): Promise { - const terminal = await this._getTerminalByIdEventually(id); - if (terminal) { - terminal._setProcessId(processId); - } - } - - public performTerminalIdAction(id: number, callback: (terminal: ExtHostTerminal) => void): void { - // TODO: Use await this._getTerminalByIdEventually(id); - let terminal = this._getTerminalById(id); - if (terminal) { - callback(terminal); - } else { - // Retry one more time in case the terminal has not yet been initialized. - setTimeout(() => { - terminal = this._getTerminalById(id); - if (terminal) { - callback(terminal); - } - }, EXT_HOST_CREATION_DELAY * 2); - } - } - private _apiInspectConfigToPlain( config: { key: string; defaultValue?: T; globalValue?: T; workspaceValue?: T, workspaceFolderValue?: T } | undefined ): { user: T | undefined, value: T | undefined, default: T | undefined } { @@ -508,7 +182,7 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT this._variableResolver, isWorkspaceShellAllowed, pkg.version, - terminalConfig.get('setLocaleVariables', false), + terminalConfig.get<'auto' | 'off' | 'on'>('detectLocale', 'auto'), baseEnv ); @@ -521,86 +195,6 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT this._setupExtHostProcessListeners(id, new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, enableConpty, this._logService)); } - public async $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise { - // Make sure the ExtHostTerminal exists so onDidOpenTerminal has fired before we call - // Pseudoterminal.start - const terminal = await this._getTerminalByIdEventually(id); - if (!terminal) { - return; - } - - // Wait for onDidOpenTerminal to fire - let openPromise: Promise; - if (terminal.isOpen) { - openPromise = Promise.resolve(); - } else { - openPromise = new Promise(r => { - // Ensure open is called after onDidOpenTerminal - const listener = this.onDidOpenTerminal(async e => { - if (e === terminal) { - listener.dispose(); - r(); - } - }); - }); - } - await openPromise; - - // 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 { - p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd)); - p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title)); - p.onProcessData(data => this._proxy.$sendProcessData(id, data)); - p.onProcessExit(exitCode => this._onProcessExit(id, exitCode)); - if (p.onProcessOverrideDimensions) { - p.onProcessOverrideDimensions(e => this._proxy.$sendOverrideDimensions(id, e)); - } - this._terminalProcesses[id] = p; - } - - public $acceptProcessInput(id: number, data: string): void { - this._terminalProcesses[id].input(data); - } - - public $acceptProcessResize(id: number, cols: number, rows: number): void { - try { - this._terminalProcesses[id].resize(cols, rows); - } catch (error) { - // We tried to write to a closed pipe / channel. - if (error.code !== 'EPIPE' && error.code !== 'ERR_IPC_CHANNEL_CLOSED') { - throw (error); - } - } - } - - public $acceptProcessShutdown(id: number, immediate: boolean): void { - this._terminalProcesses[id].shutdown(immediate); - } - - public $acceptProcessRequestInitialCwd(id: number): void { - this._terminalProcesses[id].getInitialCwd().then(initialCwd => this._proxy.$sendProcessInitialCwd(id, initialCwd)); - } - - public $acceptProcessRequestCwd(id: number): void { - this._terminalProcesses[id].getCwd().then(cwd => this._proxy.$sendProcessCwd(id, cwd)); - } - - public $acceptProcessRequestLatency(id: number): number { - return id; - } - public $requestAvailableShells(): Promise { return detectAvailableShells(); } @@ -613,138 +207,7 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT }); } - private _onProcessExit(id: number, exitCode: number): void { - // Remove process reference - delete this._terminalProcesses[id]; - - // Send exit event to main side - this._proxy.$sendProcessExit(id, exitCode); - } - - // TODO: This could be improved by using a single promise and resolve it when the terminal is ready - private _getTerminalByIdEventually(id: number, retries: number = 5): Promise { - if (!this._getTerminalPromises[id]) { - this._getTerminalPromises[id] = this._createGetTerminalPromise(id, retries); - } else { - this._getTerminalPromises[id].then(c => { - return this._createGetTerminalPromise(id, retries); - }); - } - return this._getTerminalPromises[id]; - } - - private _createGetTerminalPromise(id: number, retries: number = 5): Promise { - return new Promise(c => { - if (retries === 0) { - c(undefined); - return; - } - - const terminal = this._getTerminalById(id); - if (terminal) { - c(terminal); - } else { - // This should only be needed immediately after createTerminalRenderer is called as - // the ExtHostTerminal has not yet been iniitalized - timeout(200).then(() => c(this._createGetTerminalPromise(id, retries - 1))); - } - }); - } - - private _getTerminalById(id: number): ExtHostTerminal | null { - return this._getTerminalObjectById(this._terminals, id); - } - - private _getTerminalObjectById(array: T[], id: number): T | null { - const index = this._getTerminalObjectIndexById(array, id); - return index !== null ? array[index] : null; - } - - private _getTerminalObjectIndexById(array: T[], id: number): number | null { - let index: number | null = null; - array.some((item, i) => { - const thisId = item._id; - if (thisId === id) { - index = i; - return true; - } - return false; - }); - return index; - } - public $acceptWorkspacePermissionsChanged(isAllowed: boolean): void { this._isWorkspaceShellAllowed = isAllowed; } } - -class ApiRequest { - private _callback: (...args: any[]) => void; - private _args: any[]; - - constructor(callback: (...args: any[]) => void, args: any[]) { - this._callback = callback; - this._args = args; - } - - public run(proxy: MainThreadTerminalServiceShape, id: number) { - this._callback.apply(proxy, [id].concat(this._args)); - } -} - -class ExtHostPseudoterminal implements ITerminalChildProcess { - private readonly _onProcessData = new Emitter(); - public readonly onProcessData: Event = this._onProcessData.event; - private readonly _onProcessExit = new Emitter(); - public readonly onProcessExit: Event = this._onProcessExit.event; - private readonly _onProcessReady = new Emitter<{ pid: number, cwd: string }>(); - public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; } - private readonly _onProcessTitleChanged = new Emitter(); - public readonly onProcessTitleChanged: Event = this._onProcessTitleChanged.event; - private readonly _onProcessOverrideDimensions = new Emitter(); - public get onProcessOverrideDimensions(): Event { return this._onProcessOverrideDimensions.event; } - - constructor(private readonly _pty: vscode.Pseudoterminal) { } - - shutdown(): void { - this._pty.close(); - } - - input(data: string): void { - if (this._pty.handleInput) { - this._pty.handleInput(data); - } - } - - resize(cols: number, rows: number): void { - if (this._pty.setDimensions) { - this._pty.setDimensions({ columns: cols, rows }); - } - } - - getInitialCwd(): Promise { - return Promise.resolve(''); - } - - getCwd(): Promise { - return Promise.resolve(''); - } - - getLatency(): Promise { - return Promise.resolve(0); - } - - startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void { - // Attach the listeners - this._pty.onDidWrite(e => this._onProcessData.fire(e)); - if (this._pty.onDidClose) { - this._pty.onDidClose(e => this._onProcessExit.fire(e || 0)); - } - 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 - } - - this._pty.open(initialDimensions ? initialDimensions : undefined); - } -} - diff --git a/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts index a1a4c2f807..3db847ee1b 100644 --- a/src/vs/workbench/api/worker/extHostExtensionService.ts +++ b/src/vs/workbench/api/worker/extHostExtensionService.ts @@ -6,74 +6,10 @@ import { createApiFactoryAndRegisterActors } from 'sql/workbench/api/common/sqlExtHost.api.impl'; // {{SQL CARBON EDIT}} replace with ours import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHostExtensionActivator'; import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; -import { endsWith, startsWith } from 'vs/base/common/strings'; +import { endsWith } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; -import { joinPath } from 'vs/base/common/resources'; import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor'; -class ExportsTrap { - - static readonly Instance = new ExportsTrap(); - - private readonly _names: string[] = []; - private readonly _exports = new Map(); - - private constructor() { - - const exportsProxy = new Proxy({}, { - set: (target: any, p: PropertyKey, value: any) => { - // store in target - target[p] = value; - // store in named-bucket - const name = this._names[this._names.length - 1]; - this._exports.get(name)![p] = value; - return true; - } - }); - - - const moduleProxy = new Proxy({}, { - - get: (target: any, p: PropertyKey) => { - if (p === 'exports') { - return exportsProxy; - } - - return target[p]; - }, - - set: (target: any, p: PropertyKey, value: any) => { - // store in target - target[p] = value; - - // override bucket - if (p === 'exports') { - const name = this._names[this._names.length - 1]; - this._exports.set(name, value); - } - return true; - } - }); - - (self).exports = exportsProxy; - (self).module = moduleProxy; - } - - add(name: string) { - this._exports.set(name, Object.create(null)); - this._names.push(name); - - return { - claim: () => { - const result = this._exports.get(name); - this._exports.delete(name); - this._names.pop(); - return result; - } - }; - } -} - class WorkerRequireInterceptor extends RequireInterceptor { _installInterceptor() { } @@ -105,43 +41,33 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { await this._fakeModules.install(); } - protected _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { + protected async _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { - (self).window = self; // <- that's improper but might help extensions that aren't authored correctly + module = module.with({ path: ensureSuffix(module.path, '.js') }); + const response = await fetch(module.toString(true)); - // FAKE require function that only works for the vscode-module - const moduleStack: URI[] = []; - (self).require = (mod: string) => { + if (response.status !== 200) { + throw new Error(response.statusText); + } - const parent = moduleStack[moduleStack.length - 1]; - const result = this._fakeModules.getModule(mod, parent); + // fetch JS sources as text and create a new function around it + const initFn = new Function('module', 'exports', 'require', 'window', await response.text()); - if (result !== undefined) { - return result; + // define commonjs globals: `module`, `exports`, and `require` + const _exports = {}; + const _module = { exports: _exports }; + const _require = (request: string) => { + const result = this._fakeModules.getModule(request, module); + if (result === undefined) { + throw new Error(`Cannot load module '${request}'`); } - - if (!startsWith(mod, '.')) { - throw new Error(`Cannot load module '${mod}'`); - } - - const next = joinPath(parent, '..', ensureSuffix(mod, '.js')); - moduleStack.push(next); - const trap = ExportsTrap.Instance.add(next.toString()); - importScripts(next.toString(true)); - moduleStack.pop(); - - return trap.claim(); + return result; }; try { activationTimesBuilder.codeLoadingStart(); - module = module.with({ path: ensureSuffix(module.path, '.js') }); - moduleStack.push(module); - const trap = ExportsTrap.Instance.add(module.toString()); - importScripts(module.toString(true)); - moduleStack.pop(); - return Promise.resolve(trap.claim()); - + initFn(_module, _exports, _require, self); + return (_module.exports !== _exports ? _module.exports : _exports); } finally { activationTimesBuilder.codeLoadingStop(); } diff --git a/src/vs/workbench/api/worker/extHostLogService.ts b/src/vs/workbench/api/worker/extHostLogService.ts index 949e82ed26..8f45b9364f 100644 --- a/src/vs/workbench/api/worker/extHostLogService.ts +++ b/src/vs/workbench/api/worker/extHostLogService.ts @@ -15,7 +15,7 @@ import { localize } from 'vs/nls'; export class ExtHostLogService extends AbstractLogService implements ILogService, ExtHostLogServiceShape { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _proxy: MainThreadLogShape; private readonly _logFile: UriComponents; diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index 93c4ebd7e9..014d6e8a8a 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -234,8 +234,7 @@ export class ToggleEditorVisibilityAction extends Action { } run(): Promise { - const hideEditor = this.layoutService.isVisible(Parts.EDITOR_PART); - this.layoutService.setEditorHidden(hideEditor); + this.layoutService.toggleMaximizedPanel(); return Promise.resolve(); } diff --git a/src/vs/workbench/browser/actions/listCommands.ts b/src/vs/workbench/browser/actions/listCommands.ts index e98782f936..364c138fae 100644 --- a/src/vs/workbench/browser/actions/listCommands.ts +++ b/src/vs/workbench/browser/actions/listCommands.ts @@ -701,14 +701,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ if (!start) { scope = undefined; } else { - const selectedNode = tree.getNode(start); - const parentNode = selectedNode.parent; - - if (!parentNode || !parentNode.parent) { // root - scope = undefined; - } else { - scope = parentNode.element; - } + scope = tree.getParentElement(start); } const newSelection: unknown[] = []; diff --git a/src/vs/workbench/browser/composite.ts b/src/vs/workbench/browser/composite.ts index 8893bdbde3..5d6e447e54 100644 --- a/src/vs/workbench/browser/composite.ts +++ b/src/vs/workbench/browser/composite.ts @@ -84,8 +84,8 @@ export abstract class Composite extends Component implements IComposite { this.visible = false; } - getTitle(): string | null { - return null; + getTitle(): string | undefined { + return undefined; } protected get telemetryService(): ITelemetryService { diff --git a/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts index 28f273ce5f..b84d724bd6 100644 --- a/src/vs/workbench/browser/contextkeys.ts +++ b/src/vs/workbench/browser/contextkeys.ts @@ -8,7 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys'; import { IWindowsConfiguration } from 'vs/platform/windows/common/windows'; -import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext } from 'vs/workbench/common/editor'; +import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorIsSaveableContext, toResource, SideBySideEditor } from 'vs/workbench/common/editor'; import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom'; import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -21,6 +21,8 @@ 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'; +import { IFileService } from 'vs/platform/files/common/files'; +import { Schemas } from 'vs/base/common/network'; export const IsMacContext = new RawContextKey('isMac', isMacintosh); export const IsLinuxContext = new RawContextKey('isLinux', isLinux); @@ -52,6 +54,7 @@ export class WorkbenchContextKeysHandler extends Disposable { private inputFocusedContext: IContextKey; private activeEditorContext: IContextKey; + private activeEditorIsSaveable: IContextKey; private activeEditorGroupEmpty: IContextKey; private activeEditorGroupIndex: IContextKey; @@ -80,7 +83,8 @@ export class WorkbenchContextKeysHandler extends Disposable { @IEditorService private editorService: IEditorService, @IEditorGroupsService private editorGroupService: IEditorGroupsService, @IWorkbenchLayoutService private layoutService: IWorkbenchLayoutService, - @IViewletService private viewletService: IViewletService + @IViewletService private viewletService: IViewletService, + @IFileService private fileService: IFileService ) { super(); @@ -142,6 +146,7 @@ export class WorkbenchContextKeysHandler extends Disposable { // Editors this.activeEditorContext = ActiveEditorContext.bindTo(this.contextKeyService); + this.activeEditorIsSaveable = ActiveEditorIsSaveableContext.bindTo(this.contextKeyService); this.editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService); this.textCompareEditorVisibleContext = TextCompareEditorVisibleContext.bindTo(this.contextKeyService); this.textCompareEditorActiveContext = TextCompareEditorActiveContext.bindTo(this.contextKeyService); @@ -209,13 +214,18 @@ export class WorkbenchContextKeysHandler extends Disposable { this.multipleEditorGroupsContext.reset(); } - this.activeEditorGroupIndex.set(activeGroup.index); + this.activeEditorGroupIndex.set(activeGroup.index + 1); // not zero-indexed this.activeEditorGroupLast.set(activeGroup.index === groupCount - 1); if (activeControl) { this.activeEditorContext.set(activeControl.getId()); + + const resource = toResource(activeControl.input, { supportSideBySide: SideBySideEditor.MASTER }); + const canSave = resource ? this.fileService.canHandleResource(resource) || resource.scheme === Schemas.untitled : false; + this.activeEditorIsSaveable.set(canSave); } else { this.activeEditorContext.reset(); + this.activeEditorIsSaveable.reset(); } } diff --git a/src/vs/workbench/browser/editor.ts b/src/vs/workbench/browser/editor.ts index d9a199f719..c2e5f3c411 100644 --- a/src/vs/workbench/browser/editor.ts +++ b/src/vs/workbench/browser/editor.ts @@ -174,4 +174,4 @@ export const Extensions = { Editors: 'workbench.contributions.editors' }; -Registry.add(Extensions.Editors, new EditorRegistry()); \ No newline at end of file +Registry.add(Extensions.Editors, new EditorRegistry()); diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 5b7b0f159e..85f0a165fb 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -14,7 +14,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { IDecorationsService, IResourceDecorationChangeEvent, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; +import { IDecorationsService, IResourceDecorationChangeEvent } from 'vs/workbench/services/decorations/browser/decorations'; import { Schemas } from 'vs/base/common/network'; import { FileKind, FILES_ASSOCIATIONS_CONFIG, IFileService } from 'vs/platform/files/common/files'; import { ITextModel } from 'vs/editor/common/model'; @@ -34,7 +34,7 @@ export interface IResourceLabelProps { export interface IResourceLabelOptions extends IIconLabelValueOptions { fileKind?: FileKind; - fileDecorations?: { colors: boolean, badges: boolean, data?: IDecorationData }; + fileDecorations?: { colors: boolean, badges: boolean }; descriptionVerbosity?: Verbosity; } @@ -468,8 +468,7 @@ class ResourceLabelWidget extends IconLabel { if (this.options && this.options.fileDecorations && resource) { const deco = this.decorationsService.getDecoration( resource, - this.options.fileKind !== FileKind.FILE, - this.options.fileDecorations.data + this.options.fileKind !== FileKind.FILE ); if (deco) { diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 85264a443e..fb8b886d95 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -21,7 +21,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { ITitleService } from 'vs/workbench/services/title/common/titleService'; -import { IInstantiationService, ServicesAccessor, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { LifecyclePhase, StartupKind, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IWindowService, MenuBarVisibility, getTitleBarStyle } from 'vs/platform/windows/common/windows'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -60,6 +60,8 @@ enum Storage { PANEL_SIZE = 'workbench.panel.size', PANEL_SIZE_BEFORE_MAXIMIZED = 'workbench.panel.sizeBeforeMaximized', + EDITOR_HIDDEN = 'workbench.editor.hidden', + ZEN_MODE_ENABLED = 'workbench.zenmode.active', CENTERED_LAYOUT_ENABLED = 'workbench.centerededitorlayout.active', @@ -78,7 +80,7 @@ enum Classes { export abstract class Layout extends Disposable implements IWorkbenchLayoutService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private readonly _onTitleBarVisibilityChange: Emitter = this._register(new Emitter()); readonly onTitleBarVisibilityChange: Event = this._onTitleBarVisibilityChange.event; @@ -220,8 +222,15 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi private registerLayoutListeners(): void { // Restore editor if hidden and it changes - this._register(this.editorService.onDidVisibleEditorsChange(() => this.setEditorHidden(false))); - this._register(this.editorGroupService.onDidActivateGroup(() => this.setEditorHidden(false))); + const showEditorIfHidden = () => { + if (this.state.editor.hidden) { + this.toggleMaximizedPanel(); + } + }; + + + this._register(this.editorService.onDidVisibleEditorsChange(showEditorIfHidden)); + this._register(this.editorGroupService.onDidActivateGroup(showEditorIfHidden)); // Configuration changes this._register(this.configurationService.onDidChangeConfiguration(() => this.doUpdateLayoutConfiguration())); @@ -601,6 +610,23 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi return offset; } + getMaximumEditorDimensions(): Dimension { + const takenWidth = + (this.isVisible(Parts.ACTIVITYBAR_PART) ? this.activityBarPartView.minimumWidth : 0) + + (this.isVisible(Parts.SIDEBAR_PART) ? this.sideBarPartView.minimumWidth : 0) + + (this.isVisible(Parts.PANEL_PART) && this.state.panel.position === Position.RIGHT ? this.panelPartView.minimumWidth : 0); + + const takenHeight = + (this.isVisible(Parts.TITLEBAR_PART) ? this.titleBarPartView.minimumHeight : 0) + + (this.isVisible(Parts.STATUSBAR_PART) ? this.statusBarPartView.minimumHeight : 0) + + (this.isVisible(Parts.PANEL_PART) && this.state.panel.position === Position.BOTTOM ? this.panelPartView.minimumHeight : 0); + + const availableWidth = this.dimension.width - takenWidth; + const availableHeight = this.dimension.height - takenHeight; + + return { width: availableWidth, height: availableHeight }; + } + getWorkbenchContainer(): HTMLElement { return this.parent; } @@ -617,7 +643,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // To properly reset line numbers we need to read the configuration for each editor respecting it's uri. if (!lineNumbers && isCodeEditor(editor) && editor.hasModel()) { const model = editor.getModel(); - lineNumbers = this.configurationService.getValue('editor.lineNumbers', { resource: model.uri }); + lineNumbers = this.configurationService.getValue('editor.lineNumbers', { resource: model.uri, overrideIdentifier: model.getModeId() }); } if (!lineNumbers) { lineNumbers = this.configurationService.getValue('editor.lineNumbers'); @@ -769,16 +795,15 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi const sideBar = this.getPart(Parts.SIDEBAR_PART); const statusBar = this.getPart(Parts.STATUSBAR_PART); + // View references for all parts + this.titleBarPartView = titleBar; + this.sideBarPartView = sideBar; + this.activityBarPartView = activityBar; + this.editorPartView = editorPart; + this.panelPartView = panelPart; + this.statusBarPartView = statusBar; + if (this.configurationService.getValue('workbench.useExperimentalGridLayout')) { - - // View references for all parts - this.titleBarPartView = titleBar; - this.sideBarPartView = sideBar; - this.activityBarPartView = activityBar; - this.editorPartView = editorPart; - this.panelPartView = panelPart; - this.statusBarPartView = statusBar; - const viewMap = { [Parts.ACTIVITYBAR_PART]: this.activityBarPartView, [Parts.TITLEBAR_PART]: this.titleBarPartView, @@ -985,6 +1010,13 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Propagate to grid this.workbenchGrid.setViewVisible(this.editorPartView, !hidden); + // Remember in settings + if (hidden) { + this.storageService.store(Storage.EDITOR_HIDDEN, true, StorageScope.WORKSPACE); + } else { + this.storageService.remove(Storage.EDITOR_HIDDEN, StorageScope.WORKSPACE); + } + // The editor and panel cannot be hidden at the same time if (hidden && this.state.panel.hidden) { this.setPanelHidden(false, true); @@ -1110,7 +1142,12 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi if (this.workbenchGrid instanceof Grid) { const size = this.workbenchGrid.getViewSize(this.panelPartView); if (!this.isPanelMaximized()) { - this.state.panel.sizeBeforeMaximize = this.state.panel.position === Position.BOTTOM ? size.height : size.width; + if (this.state.panel.hidden) { + this.state.panel.sizeBeforeMaximize = this.workbenchGrid.getViewCachedVisibleSize(this.panelPartView) || this.panelPartView.minimumHeight; + } else { + this.state.panel.sizeBeforeMaximize = this.state.panel.position === Position.BOTTOM ? size.height : size.width; + } + this.storageService.store(Storage.PANEL_SIZE_BEFORE_MAXIMIZED, this.state.panel.sizeBeforeMaximize, StorageScope.GLOBAL); this.setEditorHidden(true); } else { @@ -1215,6 +1252,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // At some point, we will not fall back to old keys from legacy layout, but for now, let's migrate the keys const sideBarSize = this.storageService.getNumber(Storage.SIDEBAR_SIZE, StorageScope.GLOBAL, this.storageService.getNumber('workbench.sidebar.width', StorageScope.GLOBAL, Math.min(workbenchDimensions.width / 4, 300))!); const panelSize = this.storageService.getNumber(Storage.PANEL_SIZE, StorageScope.GLOBAL, this.storageService.getNumber(this.state.panel.position === Position.BOTTOM ? 'workbench.panel.height' : 'workbench.panel.width', StorageScope.GLOBAL, workbenchDimensions.height / 3)); + const wasEditorHidden = this.storageService.getBoolean(Storage.EDITOR_HIDDEN, StorageScope.WORKSPACE, false); const titleBarHeight = this.titleBarPartView.minimumHeight; const statusBarHeight = this.statusBarPartView.minimumHeight; @@ -1246,7 +1284,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi const panelNode: ISerializedLeafNode = { type: 'leaf', data: { type: Parts.PANEL_PART }, - size: panelSize, + size: wasEditorHidden ? this.state.panel.sizeBeforeMaximize : panelSize, visible: !this.state.panel.hidden }; diff --git a/src/vs/workbench/browser/media/part.css b/src/vs/workbench/browser/media/part.css index a9cee770a5..6b4f2c371c 100644 --- a/src/vs/workbench/browser/media/part.css +++ b/src/vs/workbench/browser/media/part.css @@ -9,6 +9,7 @@ .monaco-workbench .part { box-sizing: border-box; + overflow: hidden; } .monaco-workbench .part > .title { diff --git a/src/vs/workbench/browser/part.ts b/src/vs/workbench/browser/part.ts index 6aadf410cc..acf79e48df 100644 --- a/src/vs/workbench/browser/part.ts +++ b/src/vs/workbench/browser/part.ts @@ -33,8 +33,8 @@ export abstract class Part extends Component implements ISerializableView { get dimension(): Dimension { return this._dimension; } private parent: HTMLElement; - private titleArea: HTMLElement | null; - private contentArea: HTMLElement | null; + private titleArea: HTMLElement | null = null; + private contentArea: HTMLElement | null = null; private partLayout: PartLayout; constructor( diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 4e96f874ee..b729804ec5 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -14,7 +14,7 @@ import { GlobalActivityActionViewItem, ViewletActivityAction, ToggleViewletActio import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IBadge } from 'vs/workbench/services/activity/common/activity'; import { IWorkbenchLayoutService, Parts, Position as SideBarPosition } from 'vs/workbench/services/layout/browser/layoutService'; -import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/layoutActions'; import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; @@ -48,7 +48,7 @@ interface ICachedViewlet { export class ActivitybarPart extends Part implements IActivityBarService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private static readonly ACTION_HEIGHT = 48; private static readonly PINNED_VIEWLETS = 'workbench.activity.pinnedViewlets'; @@ -198,6 +198,8 @@ export class ActivitybarPart extends Part implements IActivityBarService { this.createGlobalActivityActionBar(globalActivities); + this.element.style.display = this.layoutService.isVisible(Parts.ACTIVITYBAR_PART) ? null : 'none'; + return content; } @@ -368,6 +370,12 @@ export class ActivitybarPart extends Part implements IActivityBarService { .map(v => v.id); } + setVisible(visible: boolean): void { + if (this.element) { + this.element.style.display = visible ? null : 'none'; + } + } + layout(width: number, height: number): void { if (!this.layoutService.isVisible(Parts.ACTIVITYBAR_PART)) { return; diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index 2251b71fa9..971ea0ea81 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -32,7 +32,6 @@ import { attachProgressBarStyler } from 'vs/platform/theme/common/styler'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { Dimension, append, $, addClass, hide, show, addClasses } from 'vs/base/browser/dom'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; -import { withNullAsUndefined } from 'vs/base/common/types'; export interface ICompositeTitleLabel { @@ -240,7 +239,7 @@ export abstract class CompositePart extends Part { // Update title with composite title if it differs from descriptor const descriptor = this.registry.getComposite(composite.getId()); if (descriptor && descriptor.name !== composite.getTitle()) { - this.updateTitle(composite.getId(), withNullAsUndefined(composite.getTitle())); + this.updateTitle(composite.getId(), composite.getTitle()); } // Handle Composite Actions diff --git a/src/vs/workbench/browser/parts/editor/baseEditor.ts b/src/vs/workbench/browser/parts/editor/baseEditor.ts index 5df7d489e9..f722d1f4d8 100644 --- a/src/vs/workbench/browser/parts/editor/baseEditor.ts +++ b/src/vs/workbench/browser/parts/editor/baseEditor.ts @@ -41,8 +41,8 @@ export abstract class BaseEditor extends Panel implements IEditor { readonly onDidSizeConstraintsChange: Event<{ width: number; height: number; } | undefined> = Event.None; - protected _input: EditorInput | null; - protected _options: EditorOptions | null; + protected _input: EditorInput | undefined; + protected _options: EditorOptions | undefined; private _group?: IEditorGroup; @@ -55,11 +55,11 @@ export abstract class BaseEditor extends Panel implements IEditor { super(id, telemetryService, themeService, storageService); } - get input(): EditorInput | null { + get input(): EditorInput | undefined { return this._input; } - get options(): EditorOptions | null { + get options(): EditorOptions | undefined { return this._options; } @@ -78,7 +78,7 @@ export abstract class BaseEditor extends Panel implements IEditor { * The provided cancellation token should be used to test if the operation * was cancelled. */ - setInput(input: EditorInput, options: EditorOptions | null, token: CancellationToken): Promise { + setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { this._input = input; this._options = options; @@ -90,8 +90,8 @@ export abstract class BaseEditor extends Panel implements IEditor { * resources associated with the input should be freed. */ clearInput(): void { - this._input = null; - this._options = null; + this._input = undefined; + this._options = undefined; } /** @@ -101,7 +101,7 @@ export abstract class BaseEditor extends Panel implements IEditor { * Sets the given options to the editor. Clients should apply the options * to the current input. */ - setOptions(options: EditorOptions | null): void { + setOptions(options: EditorOptions | undefined): void { this._options = options; } @@ -160,8 +160,8 @@ export abstract class BaseEditor extends Panel implements IEditor { } dispose(): void { - this._input = null; - this._options = null; + this._input = undefined; + this._options = undefined; super.dispose(); } @@ -172,7 +172,7 @@ interface MapGroupToMemento { } export class EditorMemento implements IEditorMemento { - private cache: LRUCache>; + private cache: LRUCache> | undefined; private cleanedUp = false; constructor( diff --git a/src/vs/workbench/browser/parts/editor/binaryEditor.ts b/src/vs/workbench/browser/parts/editor/binaryEditor.ts index 27a9793c75..b566820044 100644 --- a/src/vs/workbench/browser/parts/editor/binaryEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryEditor.ts @@ -23,7 +23,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; export interface IOpenCallbacks { - openInternal: (input: EditorInput, options: EditorOptions) => Promise; + openInternal: (input: EditorInput, options: EditorOptions | undefined) => Promise; openExternal: (uri: URI) => void; } @@ -76,7 +76,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { parent.appendChild(this.scrollbar.getDomNode()); } - async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { + async setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { await super.setInput(input, options, token); const model = await input.resolve(); @@ -102,7 +102,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { }, this.instantiationService); } - private async handleOpenInternalCallback(input: EditorInput, options: EditorOptions): Promise { + private async handleOpenInternalCallback(input: EditorInput, options: EditorOptions | undefined): Promise { await this.callbacks.openInternal(input, options); // Signal to listeners that the binary editor has been opened in-place diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbs.ts b/src/vs/workbench/browser/parts/editor/breadcrumbs.ts index bebe9c295f..0aeb3217a3 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbs.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbs.ts @@ -11,7 +11,7 @@ import { localize } from 'vs/nls'; import { IConfigurationOverrides, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Registry } from 'vs/platform/registry/common/platform'; import { GroupIdentifier } from 'vs/workbench/common/editor'; @@ -19,7 +19,7 @@ export const IBreadcrumbsService = createDecorator('IEditor export interface IBreadcrumbsService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; register(group: GroupIdentifier, widget: BreadcrumbsWidget): IDisposable; @@ -29,7 +29,7 @@ export interface IBreadcrumbsService { export class BreadcrumbsService implements IBreadcrumbsService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _map = new Map(); diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts index f78caa1eb4..4b85e3f51f 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts @@ -374,7 +374,7 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker { const labels = this._instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER /* TODO@Jo visibility propagation */); this._disposables.add(labels); - return this._instantiationService.createInstance(WorkbenchAsyncDataTree, container, new FileVirtualDelegate(), [this._instantiationService.createInstance(FileRenderer, labels)], this._instantiationService.createInstance(FileDataSource), { + return this._instantiationService.createInstance(WorkbenchAsyncDataTree, 'BreadcrumbsFilePicker', container, new FileVirtualDelegate(), [this._instantiationService.createInstance(FileRenderer, labels)], this._instantiationService.createInstance(FileDataSource), { multipleSelectionSupport: false, sorter: new FileSorter(), filter: this._instantiationService.createInstance(FileFilter), @@ -440,6 +440,7 @@ export class BreadcrumbsOutlinePicker extends BreadcrumbsPicker { protected _createTree(container: HTMLElement) { return this._instantiationService.createInstance( WorkbenchDataTree, + 'BreadcrumbsOutlinePicker', container, new OutlineVirtualDelegate(), [new OutlineGroupRenderer(), this._instantiationService.createInstance(OutlineElementRenderer)], diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index b1ed55e7e0..70663a48a9 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -52,6 +52,7 @@ import { toLocalResource } from 'vs/base/common/resources'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; // Register String Editor Registry.as(EditorExtensions.Editors).registerEditor( @@ -234,7 +235,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeEOLAction, Chang registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeEncodingAction, ChangeEncodingAction.ID, ChangeEncodingAction.LABEL), 'Change File Encoding'); export class QuickOpenActionContributor extends ActionBarContributor { - private openToSideActionInstance: OpenToSideFromQuickOpenAction; + private openToSideActionInstance: OpenToSideFromQuickOpenAction | undefined; constructor(@IInstantiationService private readonly instantiationService: IInstantiationService) { super(); @@ -417,12 +418,12 @@ editorCommands.setup(); // Touch Bar if (isMacintosh) { MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { - command: { id: NavigateBackwardsAction.ID, title: NavigateBackwardsAction.LABEL, iconLocation: { dark: URI.parse(require.toUrl('vs/workbench/browser/parts/editor/media/back-tb.png')) } }, + command: { id: NavigateBackwardsAction.ID, title: NavigateBackwardsAction.LABEL, iconLocation: { dark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/back-tb.png')) } }, group: 'navigation' }); MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { - command: { id: NavigateForwardAction.ID, title: NavigateForwardAction.LABEL, iconLocation: { dark: URI.parse(require.toUrl('vs/workbench/browser/parts/editor/media/forward-tb.png')) } }, + command: { id: NavigateForwardAction.ID, title: NavigateForwardAction.LABEL, iconLocation: { dark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/forward-tb.png')) } }, group: 'navigation' }); } @@ -452,7 +453,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands. MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All") }, group: '5_close', order: 10, when: ContextKeyExpr.has('config.workbench.editor.showTabs') }); MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: nls.localize('closeAllSaved', "Close Saved") }, group: '5_close', order: 20, when: ContextKeyExpr.has('config.workbench.editor.showTabs') }); -interface IEditorToolItem { id: string; title: string; iconDark: string; iconLight: string; } +interface IEditorToolItem { id: string; title: string; iconDark: URI; iconLight: URI; } function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | undefined, order: number, alternative?: IEditorToolItem): void { const item: IMenuItem = { @@ -460,8 +461,8 @@ function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | u id: primary.id, title: primary.title, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/browser/parts/editor/media/${primary.iconDark}`)), - light: URI.parse(require.toUrl(`vs/workbench/browser/parts/editor/media/${primary.iconLight}`)) + dark: primary.iconDark, + light: primary.iconLight } }, group: 'navigation', @@ -474,8 +475,8 @@ function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | u id: alternative.id, title: alternative.title, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/browser/parts/editor/media/${alternative.iconDark}`)), - light: URI.parse(require.toUrl(`vs/workbench/browser/parts/editor/media/${alternative.iconLight}`)) + dark: alternative.iconDark, + light: alternative.iconLight } }; } @@ -483,21 +484,26 @@ function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | u MenuRegistry.appendMenuItem(MenuId.EditorTitle, item); } +const SPLIT_EDITOR_HORIZONTAL_DARK_ICON = URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-horizontal-dark.svg')); +const SPLIT_EDITOR_HORIZONTAL_LIGHT_ICON = URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-horizontal-light.svg')); +const SPLIT_EDITOR_VERTICAL_DARK_ICON = URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-vertical-dark.svg')); +const SPLIT_EDITOR_VERTICAL_LIGHT_ICON = URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-vertical-light.svg')); + // Editor Title Menu: Split Editor appendEditorToolItem( { id: SplitEditorAction.ID, title: nls.localize('splitEditorRight', "Split Editor Right"), - iconDark: 'split-editor-horizontal-dark.svg', - iconLight: 'split-editor-horizontal-light.svg' + iconDark: SPLIT_EDITOR_HORIZONTAL_DARK_ICON, + iconLight: SPLIT_EDITOR_HORIZONTAL_LIGHT_ICON }, ContextKeyExpr.not('splitEditorsVertically'), 100000, // towards the end { id: editorCommands.SPLIT_EDITOR_DOWN, title: nls.localize('splitEditorDown', "Split Editor Down"), - iconDark: 'split-editor-vertical-dark.svg', - iconLight: 'split-editor-vertical-light.svg' + iconDark: SPLIT_EDITOR_VERTICAL_DARK_ICON, + iconLight: SPLIT_EDITOR_VERTICAL_LIGHT_ICON } ); @@ -505,34 +511,37 @@ appendEditorToolItem( { id: SplitEditorAction.ID, title: nls.localize('splitEditorDown', "Split Editor Down"), - iconDark: 'split-editor-vertical-dark.svg', - iconLight: 'split-editor-vertical-light.svg' + iconDark: SPLIT_EDITOR_VERTICAL_DARK_ICON, + iconLight: SPLIT_EDITOR_VERTICAL_LIGHT_ICON }, ContextKeyExpr.has('splitEditorsVertically'), 100000, // towards the end { id: editorCommands.SPLIT_EDITOR_RIGHT, title: nls.localize('splitEditorRight', "Split Editor Right"), - iconDark: 'split-editor-horizontal-dark.svg', - iconLight: 'split-editor-horizontal-light.svg' + iconDark: SPLIT_EDITOR_HORIZONTAL_DARK_ICON, + iconLight: SPLIT_EDITOR_HORIZONTAL_LIGHT_ICON } ); +const CLOSE_ALL_DARK_ICON = URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-all-dark.svg')); +const CLOSE_ALL_LIGHT_ICON = URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-all-light.svg')); + // Editor Title Menu: Close Group (tabs disabled) appendEditorToolItem( { id: editorCommands.CLOSE_EDITOR_COMMAND_ID, title: nls.localize('close', "Close"), - iconDark: 'close-dark-alt.svg', - iconLight: 'close-light-alt.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-dark-alt.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-light-alt.svg')) }, ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ContextKeyExpr.not('groupActiveEditorDirty')), 1000000, // towards the far end { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All"), - iconDark: 'close-all-dark.svg', - iconLight: 'close-all-light.svg' + iconDark: CLOSE_ALL_DARK_ICON, + iconLight: CLOSE_ALL_LIGHT_ICON } ); @@ -540,16 +549,16 @@ appendEditorToolItem( { id: editorCommands.CLOSE_EDITOR_COMMAND_ID, title: nls.localize('close', "Close"), - iconDark: 'close-dirty-dark-alt.svg', - iconLight: 'close-dirty-light-alt.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-dirty-dark-alt.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-dirty-light-alt.svg')) }, ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ContextKeyExpr.has('groupActiveEditorDirty')), 1000000, // towards the far end { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All"), - iconDark: 'close-all-dark.svg', - iconLight: 'close-all-light.svg' + iconDark: CLOSE_ALL_DARK_ICON, + iconLight: CLOSE_ALL_LIGHT_ICON } ); @@ -558,8 +567,8 @@ appendEditorToolItem( { id: editorCommands.GOTO_PREVIOUS_CHANGE, title: nls.localize('navigate.prev.label', "Previous Change"), - iconDark: 'previous-diff-dark.svg', - iconLight: 'previous-diff-light.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/previous-diff-dark.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/previous-diff-light.svg')) }, TextCompareEditorActiveContext, 10 @@ -570,8 +579,8 @@ appendEditorToolItem( { id: editorCommands.GOTO_NEXT_CHANGE, title: nls.localize('navigate.next.label', "Next Change"), - iconDark: 'next-diff-dark.svg', - iconLight: 'next-diff-light.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/next-diff-dark.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/next-diff-light.svg')) }, TextCompareEditorActiveContext, 11 @@ -582,8 +591,8 @@ appendEditorToolItem( { id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE, title: nls.localize('ignoreTrimWhitespace.label', "Ignore Trim Whitespace"), - iconDark: 'paragraph-dark.svg', - iconLight: 'paragraph-light.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-dark.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-light.svg')) }, ContextKeyExpr.and(TextCompareEditorActiveContext, ContextKeyExpr.notEquals('config.diffEditor.ignoreTrimWhitespace', true)), 20 @@ -594,8 +603,8 @@ appendEditorToolItem( { id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE, title: nls.localize('showTrimWhitespace.label', "Show Trim Whitespace"), - iconDark: 'paragraph-disabled-dark.svg', - iconLight: 'paragraph-disabled-light.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-disabled-dark.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-disabled-light.svg')) }, ContextKeyExpr.and(TextCompareEditorActiveContext, ContextKeyExpr.notEquals('config.diffEditor.ignoreTrimWhitespace', false)), 20 diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index a7bc942c10..d66cae2594 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -263,7 +263,10 @@ function registerDiffEditorCommands(): void { const candidates = [editorService.activeControl, ...editorService.visibleControls].filter(e => e instanceof TextDiffEditor); if (candidates.length > 0) { - next ? (candidates[0]).getDiffNavigator().next() : (candidates[0]).getDiffNavigator().previous(); + const navigator = (candidates[0]).getDiffNavigator(); + if (navigator) { + next ? navigator.next() : navigator.previous(); + } } } diff --git a/src/vs/workbench/browser/parts/editor/editorControl.ts b/src/vs/workbench/browser/parts/editor/editorControl.ts index 0a28973189..4941dbea18 100644 --- a/src/vs/workbench/browser/parts/editor/editorControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorControl.ts @@ -15,7 +15,6 @@ import { IEditorProgressService, LongRunningOperation } from 'vs/platform/progre import { IEditorGroupView, DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor'; import { Event, Emitter } from 'vs/base/common/event'; import { IVisibleEditor } from 'vs/workbench/services/editor/common/editorService'; -import { withUndefinedAsNull } from 'vs/base/common/types'; export interface IOpenEditorResult { readonly control: BaseEditor; @@ -35,11 +34,11 @@ export class EditorControl extends Disposable { private _onDidSizeConstraintsChange = this._register(new Emitter<{ width: number; height: number; } | undefined>()); get onDidSizeConstraintsChange(): Event<{ width: number; height: number; } | undefined> { return this._onDidSizeConstraintsChange.event; } - private _activeControl: BaseEditor | null; + private _activeControl: BaseEditor | null = null; private controls: BaseEditor[] = []; private readonly activeControlDisposables = this._register(new DisposableStore()); - private dimension: Dimension; + private dimension: Dimension | undefined; private editorOperation: LongRunningOperation; constructor( @@ -68,7 +67,7 @@ export class EditorControl extends Disposable { const control = this.doShowEditorControl(descriptor); // Set input - const editorChanged = await this.doSetInput(control, editor, withUndefinedAsNull(options)); + const editorChanged = await this.doSetInput(control, editor, options); return { control, editorChanged }; } @@ -151,7 +150,7 @@ export class EditorControl extends Disposable { this._onDidSizeConstraintsChange.fire(undefined); } - private async doSetInput(control: BaseEditor, editor: EditorInput, options: EditorOptions | null): Promise { + private async doSetInput(control: BaseEditor, editor: EditorInput, options: EditorOptions | undefined): Promise { // If the input did not change, return early and only apply the options // unless the options instruct us to force open it even if it is the same diff --git a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts index c2ec00218b..4fde15e688 100644 --- a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts +++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts @@ -25,11 +25,11 @@ class DropOverlay extends Themable { private static OVERLAY_ID = 'monaco-workbench-editor-drop-overlay'; - private container: HTMLElement; - private overlay: HTMLElement; + private container!: HTMLElement; + private overlay!: HTMLElement; - private currentDropOperation?: IDropOperation; - private _disposed: boolean; + private currentDropOperation: IDropOperation | undefined; + private _disposed: boolean | undefined; private cleanupOverlayScheduler: RunOnceScheduler; @@ -50,7 +50,7 @@ class DropOverlay extends Themable { } get disposed(): boolean { - return this._disposed; + return !!this._disposed; } private create(): void { diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 97441b6945..9be335550b 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -817,7 +817,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { this._onWillOpenEditor.fire(event); const prevented = event.isPrevented(); if (prevented) { - return prevented(); + return withUndefinedAsNull(await prevented()); } // Proceed with opening @@ -846,9 +846,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView { if (options && options.activation === EditorActivation.ACTIVATE) { // Respect option to force activate an editor group. activateGroup = true; + } else if (options && options.activation === EditorActivation.RESTORE) { + // Respect option to force restore an editor group. + restoreGroup = true; } else if (options && options.activation === EditorActivation.PRESERVE) { // Respect option to preserve active editor group. activateGroup = false; + restoreGroup = false; } else if (openEditorOptions.active) { // Finally, we only activate/restore an editor which is // opening as active editor. @@ -1524,7 +1528,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } class EditorOpeningEvent implements IEditorOpeningEvent { - private override: () => Promise; + private override: () => Promise; constructor( private _group: GroupIdentifier, @@ -1545,11 +1549,11 @@ class EditorOpeningEvent implements IEditorOpeningEvent { return this._options; } - prevent(callback: () => Promise): void { + prevent(callback: () => Promise): void { this.override = callback; } - isPrevented(): () => Promise { + isPrevented(): () => Promise { return this.override; } } diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index f2725eb1eb..e8299b3a82 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -10,7 +10,7 @@ import { Dimension, isAncestor, toggleClass, addClass, $ } from 'vs/base/browser 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 { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; 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'; @@ -81,7 +81,7 @@ class GridWidgetView implements IView { export class EditorPart extends Part implements IEditorGroupsService, IEditorGroupsAccessor { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private static readonly EDITOR_PART_UI_STATE_STORAGE_KEY = 'editorpart.state'; private static readonly EDITOR_PART_CENTERED_VIEW_STORAGE_KEY = 'editorpart.centeredview'; @@ -140,7 +140,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro @IThemeService themeService: IThemeService, @IConfigurationService private readonly configurationService: IConfigurationService, @IStorageService storageService: IStorageService, - @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService + @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService ) { super(Parts.EDITOR_PART, { hasTitle: false }, themeService, storageService, layoutService); @@ -780,14 +780,15 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro //#region Part - get minimumWidth(): number { return this.centeredLayoutWidget.minimumWidth; } + // TODO @sbatten @joao find something better to prevent editor taking over #79897 + get minimumWidth(): number { return Math.min(this.centeredLayoutWidget.minimumWidth, this.layoutService.getMaximumEditorDimensions().width); } get maximumWidth(): number { return this.centeredLayoutWidget.maximumWidth; } - get minimumHeight(): number { return this.centeredLayoutWidget.minimumHeight; } + get minimumHeight(): number { return Math.min(this.centeredLayoutWidget.minimumHeight, this.layoutService.getMaximumEditorDimensions().height); } get maximumHeight(): number { return this.centeredLayoutWidget.maximumHeight; } readonly snap = true; - get onDidChange(): Event { return this.centeredLayoutWidget.onDidChange; } + get onDidChange(): Event { return Event.any(this.centeredLayoutWidget.onDidChange, this.onDidSetGridWidget.event); } readonly priority: LayoutPriority = LayoutPriority.High; private get gridSeparatorBorder(): Color { diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 55c5fab68c..5b88807bd3 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -35,7 +35,7 @@ import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/c import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ITextFileService, SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; -import { IConfigurationChangedEvent, IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { deepClone } from 'vs/base/common/objects'; @@ -328,7 +328,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { if (!this.screenReaderNotification) { this.screenReaderNotification = this.notificationService.prompt( Severity.Info, - nls.localize('screenReaderDetectedExplanation.question', "Are you using a screen reader to operate Azure Data Studio? (Certain features like folding, minimap or word wrap are disabled when using a screen reader)"), + nls.localize('screenReaderDetectedExplanation.question', "Are you using a screen reader to operate Azure Data Studio? (Certain features like word wrap are disabled when using a screen reader)"), // {{SQL CARBON EDIT}} change vscode to ads [{ label: nls.localize('screenReaderDetectedExplanation.answerYes', "Yes"), run: () => { @@ -586,8 +586,8 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { if (activeCodeEditor) { // Hook Listener for Configuration changes - this.activeEditorListeners.add(activeCodeEditor.onDidChangeConfiguration((event: IConfigurationChangedEvent) => { - if (event.accessibilitySupport) { + this.activeEditorListeners.add(activeCodeEditor.onDidChangeConfiguration((event: ConfigurationChangedEvent) => { + if (event.hasChanged(EditorOption.accessibilitySupport)) { this.onScreenReaderModeChange(activeCodeEditor); } })); @@ -711,7 +711,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } } - screenReaderMode = (editorWidget.getConfiguration().accessibilitySupport === AccessibilitySupport.Enabled); + screenReaderMode = (editorWidget.getOption(EditorOption.accessibilitySupport) === AccessibilitySupport.Enabled); } if (screenReaderMode === false && this.screenReaderNotification) { @@ -761,7 +761,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { private onEOLChange(editorWidget: ICodeEditor | undefined): void { const info: StateDelta = { EOL: undefined }; - if (editorWidget && !editorWidget.getConfiguration().readOnly) { + if (editorWidget && !editorWidget.getOption(EditorOption.readOnly)) { const codeEditorModel = editorWidget.getModel(); if (codeEditorModel) { info.EOL = codeEditorModel.getEOL(); @@ -822,8 +822,7 @@ function isWritableCodeEditor(codeEditor: ICodeEditor | undefined): boolean { if (!codeEditor) { return false; } - const config = codeEditor.getConfiguration(); - return (!config.readOnly); + return !codeEditor.getOption(EditorOption.readOnly); } function isWritableBaseEditor(e: IBaseEditor): boolean { @@ -1169,7 +1168,7 @@ export class ChangeEncodingAction extends Action { let guessedEncoding: string | undefined = undefined; if (this.fileService.canHandleResource(resource)) { - const content = await this.textFileService.read(resource, { autoGuessEncoding: true, acceptTextOnly: true }); + const content = await this.textFileService.read(resource, { autoGuessEncoding: true }); guessedEncoding = content.encoding; } diff --git a/src/vs/workbench/browser/parts/editor/media/close-dirty-inverse-alt.svg b/src/vs/workbench/browser/parts/editor/media/close-dirty-inverse-alt.svg deleted file mode 100644 index 02dafab76f..0000000000 --- a/src/vs/workbench/browser/parts/editor/media/close-dirty-inverse-alt.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/editor/media/close-dirty-inverse.svg b/src/vs/workbench/browser/parts/editor/media/close-dirty-inverse.svg deleted file mode 100644 index 02dafab76f..0000000000 --- a/src/vs/workbench/browser/parts/editor/media/close-dirty-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css b/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css index d505c304cd..f95c8de3c9 100644 --- a/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css +++ b/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css @@ -81,6 +81,7 @@ display: flex; flex: initial; opacity: 0.5; + padding-right: 8px; height: 35px; } diff --git a/src/vs/workbench/browser/parts/editor/media/resourceviewer.css b/src/vs/workbench/browser/parts/editor/media/resourceviewer.css index 342c93432f..507b3f6be9 100644 --- a/src/vs/workbench/browser/parts/editor/media/resourceviewer.css +++ b/src/vs/workbench/browser/parts/editor/media/resourceviewer.css @@ -12,52 +12,6 @@ box-sizing: border-box; } -.monaco-resource-viewer.image { - padding: 0; - display: flex; - box-sizing: border-box; -} - -.monaco-resource-viewer.image img { - padding: 0; - background-position: 0 0, 8px 8px; - background-size: 16px 16px; -} - -.vs .monaco-resource-viewer.image img { - background-image: - linear-gradient(45deg, rgb(230, 230, 230) 25%, transparent 25%, transparent 75%, rgb(230, 230, 230) 75%, rgb(230, 230, 230)), - linear-gradient(45deg, rgb(230, 230, 230) 25%, transparent 25%, transparent 75%, rgb(230, 230, 230) 75%, rgb(230, 230, 230)); -} - -.vs-dark .monaco-resource-viewer.image img { - background-image: - linear-gradient(45deg, rgb(20, 20, 20) 25%, transparent 25%, transparent 75%, rgb(20, 20, 20) 75%, rgb(20, 20, 20)), - linear-gradient(45deg, rgb(20, 20, 20) 25%, transparent 25%, transparent 75%, rgb(20, 20, 20) 75%, rgb(20, 20, 20)); -} - -.monaco-resource-viewer img.pixelated { - image-rendering: pixelated; -} - -.monaco-resource-viewer img.scale-to-fit { - max-width: calc(100% - 20px); - max-height: calc(100% - 20px); - object-fit: contain; -} - -.monaco-resource-viewer img { - margin: auto; -} - -.monaco-resource-viewer.zoom-in { - cursor: zoom-in; -} - -.monaco-resource-viewer.zoom-out { - cursor: zoom-out; -} - .monaco-resource-viewer .embedded-link, .monaco-resource-viewer .embedded-link:hover { cursor: pointer; diff --git a/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css b/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css index 6719f0bf24..afa43434d6 100644 --- a/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css +++ b/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css @@ -268,7 +268,7 @@ .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions { cursor: default; flex: initial; - padding-left: 4px; + padding: 0 8px 0 4px; height: 35px; } diff --git a/src/vs/workbench/browser/parts/editor/resourceViewer.ts b/src/vs/workbench/browser/parts/editor/resourceViewer.ts index 8424c004c9..94a4c36a3d 100644 --- a/src/vs/workbench/browser/parts/editor/resourceViewer.ts +++ b/src/vs/workbench/browser/parts/editor/resourceViewer.ts @@ -3,25 +3,16 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!./media/resourceviewer'; -import * as nls from 'vs/nls'; -import * as mimes from 'vs/base/common/mime'; -import { URI } from 'vs/base/common/uri'; import * as DOM from 'vs/base/browser/dom'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; -import { LRUCache } from 'vs/base/common/map'; +import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; -import { clamp } from 'vs/base/common/numbers'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IDisposable, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { Action } from 'vs/base/common/actions'; -import { memoize } from 'vs/base/common/decorators'; -import * as platform from 'vs/base/common/platform'; +import { URI } from 'vs/base/common/uri'; +import 'vs/css!./media/resourceviewer'; +import * as nls from 'vs/nls'; import { IFileService } from 'vs/platform/files/common/files'; -import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ITheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; +import { ICssStyleCollector, ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { IMAGE_PREVIEW_BORDER } from 'vs/workbench/common/theme'; export interface IResourceDescriptor { @@ -94,11 +85,6 @@ export class ResourceViewer { // Ensure CSS class container.className = 'monaco-resource-viewer'; - // Images - if (ResourceViewer.isImageResource(descriptor)) { - return ImageView.create(container, descriptor, fileService, scrollbar, delegate, instantiationService); - } - // Large Files if (descriptor.size > ResourceViewer.MAX_OPEN_INTERNAL_SIZE) { return FileTooLargeFileView.create(container, descriptor, scrollbar, delegate); @@ -110,82 +96,8 @@ export class ResourceViewer { } } - private static isImageResource(descriptor: IResourceDescriptor) { - const mime = getMime(descriptor); - - // Chrome does not support tiffs - return mime.indexOf('image/') >= 0 && mime !== 'image/tiff'; - } } -class ImageView { - private static readonly MAX_IMAGE_SIZE = BinarySize.MB * 10; // showing images inline is memory intense, so we have a limit - private static readonly BASE64_MARKER = 'base64,'; - - static create( - container: HTMLElement, - descriptor: IResourceDescriptor, - fileService: IFileService, - scrollbar: DomScrollableElement, - delegate: ResourceViewerDelegate, - instantiationService: IInstantiationService, - ): ResourceViewerContext { - if (ImageView.shouldShowImageInline(descriptor)) { - return InlineImageView.create(container, descriptor, fileService, scrollbar, delegate, instantiationService); - } - - return LargeImageView.create(container, descriptor, delegate); - } - - private static shouldShowImageInline(descriptor: IResourceDescriptor): boolean { - let skipInlineImage: boolean; - - // Data URI - if (descriptor.resource.scheme === Schemas.data) { - const base64MarkerIndex = descriptor.resource.path.indexOf(ImageView.BASE64_MARKER); - const hasData = base64MarkerIndex >= 0 && descriptor.resource.path.substring(base64MarkerIndex + ImageView.BASE64_MARKER.length).length > 0; - - skipInlineImage = !hasData || descriptor.size > ImageView.MAX_IMAGE_SIZE || descriptor.resource.path.length > ImageView.MAX_IMAGE_SIZE; - } - - // File URI - else { - skipInlineImage = typeof descriptor.size !== 'number' || descriptor.size > ImageView.MAX_IMAGE_SIZE; - } - - return !skipInlineImage; - } -} - -class LargeImageView { - static create( - container: HTMLElement, - descriptor: IResourceDescriptor, - delegate: ResourceViewerDelegate - ) { - const size = BinarySize.formatSize(descriptor.size); - delegate.metadataClb(size); - - DOM.clearNode(container); - - const disposables = new DisposableStore(); - - const label = document.createElement('p'); - label.textContent = nls.localize('largeImageError', "The image is not displayed in the editor because it is too large ({0}).", size); - container.appendChild(label); - - const openExternal = delegate.openExternalClb; - if (descriptor.resource.scheme === Schemas.file && openExternal) { - const link = DOM.append(label, DOM.$('a.embedded-link')); - link.setAttribute('role', 'button'); - link.textContent = nls.localize('resourceOpenExternalButton', "Open image using external program?"); - - disposables.add(DOM.addDisposableListener(link, DOM.EventType.CLICK, () => openExternal(descriptor.resource))); - } - - return disposables; - } -} class FileTooLargeFileView { static create( @@ -239,349 +151,3 @@ class FileSeemsBinaryFileView { return disposables; } } - -type Scale = number | 'fit'; - -export class ZoomStatusbarItem extends Disposable { - - private statusbarItem?: IStatusbarEntryAccessor; - - constructor( - private readonly onSelectScale: (scale: Scale) => void, - @IEditorService editorService: IEditorService, - @IContextMenuService private readonly contextMenuService: IContextMenuService, - @IStatusbarService private readonly statusbarService: IStatusbarService, - ) { - super(); - this._register(editorService.onDidActiveEditorChange(() => { - if (this.statusbarItem) { - this.statusbarItem.dispose(); - this.statusbarItem = undefined; - } - })); - } - - updateStatusbar(scale: Scale): void { - const entry: IStatusbarEntry = { - text: this.zoomLabel(scale) - }; - - if (!this.statusbarItem) { - this.statusbarItem = this.statusbarService.addEntry(entry, 'status.imageZoom', nls.localize('status.imageZoom', "Image Zoom"), StatusbarAlignment.RIGHT, 101 /* to the left of editor status (100) */); - - this._register(this.statusbarItem); - - const element = document.getElementById('status.imageZoom')!; - this._register(DOM.addDisposableListener(element, DOM.EventType.CLICK, (e: MouseEvent) => { - this.contextMenuService.showContextMenu({ - getAnchor: () => element, - getActions: () => this.zoomActions - }); - })); - } else { - this.statusbarItem.update(entry); - } - } - - @memoize - private get zoomActions(): Action[] { - const scales: Scale[] = [10, 5, 2, 1, 0.5, 0.2, 'fit']; - return scales.map(scale => - new Action(`zoom.${scale}`, this.zoomLabel(scale), undefined, undefined, () => { - this.updateStatusbar(scale); - if (this.onSelectScale) { - this.onSelectScale(scale); - } - - return Promise.resolve(undefined); - })); - } - - private zoomLabel(scale: Scale): string { - return scale === 'fit' - ? nls.localize('zoom.action.fit.label', 'Whole Image') - : `${Math.round(scale * 100)}%`; - } -} - -interface ImageState { - scale: Scale; - offsetX: number; - offsetY: number; -} - -class InlineImageView { - private static readonly SCALE_PINCH_FACTOR = 0.075; - private static readonly MAX_SCALE = 20; - private static readonly MIN_SCALE = 0.1; - - private static readonly zoomLevels: Scale[] = [ - 0.1, - 0.2, - 0.3, - 0.4, - 0.5, - 0.6, - 0.7, - 0.8, - 0.9, - 1, - 1.5, - 2, - 3, - 5, - 7, - 10, - 15, - 20 - ]; - - /** - * Enable image-rendering: pixelated for images scaled by more than this. - */ - private static readonly PIXELATION_THRESHOLD = 3; - - /** - * Store the scale and position of an image so it can be restored when changing editor tabs - */ - private static readonly imageStateCache = new LRUCache(100); - - static create( - container: HTMLElement, - descriptor: IResourceDescriptor, - fileService: IFileService, - scrollbar: DomScrollableElement, - delegate: ResourceViewerDelegate, - @IInstantiationService instantiationService: IInstantiationService, - ) { - const disposables = new DisposableStore(); - - const zoomStatusbarItem = disposables.add(instantiationService.createInstance(ZoomStatusbarItem, - newScale => updateScale(newScale))); - - const context: ResourceViewerContext = { - layout(dimension: DOM.Dimension) { }, - dispose: () => disposables.dispose() - }; - - const cacheKey = `${descriptor.resource.toString()}:${descriptor.etag}`; - - let ctrlPressed = false; - let altPressed = false; - - const initialState: ImageState = InlineImageView.imageStateCache.get(cacheKey) || { scale: 'fit', offsetX: 0, offsetY: 0 }; - let scale = initialState.scale; - let image: HTMLImageElement | null = null; - - function updateScale(newScale: Scale) { - if (!image || !image.parentElement) { - return; - } - - if (newScale === 'fit') { - scale = 'fit'; - DOM.addClass(image, 'scale-to-fit'); - DOM.removeClass(image, 'pixelated'); - image.style.minWidth = 'auto'; - image.style.width = 'auto'; - InlineImageView.imageStateCache.delete(cacheKey); - } else { - const oldWidth = image.width; - const oldHeight = image.height; - - scale = clamp(newScale, InlineImageView.MIN_SCALE, InlineImageView.MAX_SCALE); - if (scale >= InlineImageView.PIXELATION_THRESHOLD) { - DOM.addClass(image, 'pixelated'); - } else { - DOM.removeClass(image, 'pixelated'); - } - - const { scrollTop, scrollLeft } = image.parentElement; - const dx = (scrollLeft + image.parentElement.clientWidth / 2) / image.parentElement.scrollWidth; - const dy = (scrollTop + image.parentElement.clientHeight / 2) / image.parentElement.scrollHeight; - - DOM.removeClass(image, 'scale-to-fit'); - image.style.minWidth = `${(image.naturalWidth * scale)}px`; - image.style.width = `${(image.naturalWidth * scale)}px`; - - const newWidth = image.width; - const scaleFactor = (newWidth - oldWidth) / oldWidth; - - const newScrollLeft = ((oldWidth * scaleFactor * dx) + scrollLeft); - const newScrollTop = ((oldHeight * scaleFactor * dy) + scrollTop); - scrollbar.setScrollPosition({ - scrollLeft: newScrollLeft, - scrollTop: newScrollTop, - }); - - InlineImageView.imageStateCache.set(cacheKey, { scale: scale, offsetX: newScrollLeft, offsetY: newScrollTop }); - } - - zoomStatusbarItem.updateStatusbar(scale); - scrollbar.scanDomNode(); - } - - function firstZoom() { - if (!image) { - return; - } - - scale = image.clientWidth / image.naturalWidth; - updateScale(scale); - } - - disposables.add(DOM.addDisposableListener(window, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { - if (!image) { - return; - } - ctrlPressed = e.ctrlKey; - altPressed = e.altKey; - - if (platform.isMacintosh ? altPressed : ctrlPressed) { - DOM.removeClass(container, 'zoom-in'); - DOM.addClass(container, 'zoom-out'); - } - })); - - disposables.add(DOM.addDisposableListener(window, DOM.EventType.KEY_UP, (e: KeyboardEvent) => { - if (!image) { - return; - } - - ctrlPressed = e.ctrlKey; - altPressed = e.altKey; - - if (!(platform.isMacintosh ? altPressed : ctrlPressed)) { - DOM.removeClass(container, 'zoom-out'); - DOM.addClass(container, 'zoom-in'); - } - })); - - disposables.add(DOM.addDisposableListener(container, DOM.EventType.CLICK, (e: MouseEvent) => { - if (!image) { - return; - } - - if (e.button !== 0) { - return; - } - - // left click - if (scale === 'fit') { - firstZoom(); - } - - if (!(platform.isMacintosh ? altPressed : ctrlPressed)) { // zoom in - let i = 0; - for (; i < InlineImageView.zoomLevels.length; ++i) { - if (InlineImageView.zoomLevels[i] > scale) { - break; - } - } - updateScale(InlineImageView.zoomLevels[i] || InlineImageView.MAX_SCALE); - } else { - let i = InlineImageView.zoomLevels.length - 1; - for (; i >= 0; --i) { - if (InlineImageView.zoomLevels[i] < scale) { - break; - } - } - updateScale(InlineImageView.zoomLevels[i] || InlineImageView.MIN_SCALE); - } - })); - - disposables.add(DOM.addDisposableListener(container, DOM.EventType.WHEEL, (e: WheelEvent) => { - if (!image) { - return; - } - - const isScrollWheelKeyPressed = platform.isMacintosh ? altPressed : ctrlPressed; - if (!isScrollWheelKeyPressed && !e.ctrlKey) { // pinching is reported as scroll wheel + ctrl - return; - } - - e.preventDefault(); - e.stopPropagation(); - - if (scale === 'fit') { - firstZoom(); - } - - let delta = e.deltaY > 0 ? 1 : -1; - - updateScale(scale as number * (1 - delta * InlineImageView.SCALE_PINCH_FACTOR)); - })); - - disposables.add(DOM.addDisposableListener(container, DOM.EventType.SCROLL, () => { - if (!image || !image.parentElement || scale === 'fit') { - return; - } - - const entry = InlineImageView.imageStateCache.get(cacheKey); - if (entry) { - const { scrollTop, scrollLeft } = image.parentElement; - InlineImageView.imageStateCache.set(cacheKey, { scale: entry.scale, offsetX: scrollLeft, offsetY: scrollTop }); - } - })); - - DOM.clearNode(container); - DOM.addClasses(container, 'image', 'zoom-in'); - - image = DOM.append(container, DOM.$('img.scale-to-fit')); - image.style.visibility = 'hidden'; - - disposables.add(DOM.addDisposableListener(image, DOM.EventType.LOAD, e => { - if (!image) { - return; - } - if (typeof descriptor.size === 'number') { - delegate.metadataClb(nls.localize('imgMeta', '{0}x{1} {2}', image.naturalWidth, image.naturalHeight, BinarySize.formatSize(descriptor.size))); - } else { - delegate.metadataClb(nls.localize('imgMetaNoSize', '{0}x{1}', image.naturalWidth, image.naturalHeight)); - } - - scrollbar.scanDomNode(); - image.style.visibility = 'visible'; - updateScale(scale); - if (initialState.scale !== 'fit') { - scrollbar.setScrollPosition({ - scrollLeft: initialState.offsetX, - scrollTop: initialState.offsetY, - }); - } - })); - - InlineImageView.imageSrc(descriptor, fileService).then(src => { - const img = container.querySelector('img'); - if (img) { - if (typeof src === 'string') { - img.src = src; - } else { - const url = URL.createObjectURL(src); - disposables.add(toDisposable(() => URL.revokeObjectURL(url))); - img.src = url; - } - } - }); - - return context; - } - - private static async imageSrc(descriptor: IResourceDescriptor, fileService: IFileService): Promise { - if (descriptor.resource.scheme === Schemas.data) { - return descriptor.resource.toString(true /* skip encoding */); - } - - const { value } = await fileService.readFile(descriptor.resource); - return new Blob([value.buffer], { type: getMime(descriptor) }); - } -} - -function getMime(descriptor: IResourceDescriptor) { - let mime: string | undefined = descriptor.mime; - if (!mime && descriptor.resource.scheme !== Schemas.data) { - mime = mimes.getMediaMime(descriptor.resource.path); - } - - return mime || mimes.MIME_BINARY; -} diff --git a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts index 4cbb73c524..efd9b69653 100644 --- a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts +++ b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts @@ -93,20 +93,20 @@ export class SideBySideEditor extends BaseEditor { this.updateStyles(); } - async setInput(newInput: EditorInput, options: EditorOptions, token: CancellationToken): Promise { + async setInput(newInput: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { const oldInput = this.input as SideBySideEditorInput; await super.setInput(newInput, options, token); return this.updateInput(oldInput, (newInput as SideBySideEditorInput), options, token); } - setOptions(options: EditorOptions): void { + setOptions(options: EditorOptions | undefined): void { if (this.masterEditor) { this.masterEditor.setOptions(options); } } - protected setEditorVisible(visible: boolean, group: IEditorGroup): void { + protected setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void { if (this.masterEditor) { this.masterEditor.setVisible(visible, group); } @@ -159,7 +159,7 @@ export class SideBySideEditor extends BaseEditor { return this.detailsEditor; } - private async updateInput(oldInput: SideBySideEditorInput, newInput: SideBySideEditorInput, options: EditorOptions, token: CancellationToken): Promise { + private async updateInput(oldInput: SideBySideEditorInput, newInput: SideBySideEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { if (!newInput.matches(oldInput)) { if (oldInput) { this.disposeEditors(); @@ -173,12 +173,12 @@ export class SideBySideEditor extends BaseEditor { } await Promise.all([ - this.detailsEditor.setInput(newInput.details, null, token), + this.detailsEditor.setInput(newInput.details, undefined, token), this.masterEditor.setInput(newInput.master, options, token) ]); } - private setNewInput(newInput: SideBySideEditorInput, options: EditorOptions, token: CancellationToken): Promise { + private setNewInput(newInput: SideBySideEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { const detailsEditor = this.doCreateEditor(newInput.details, this.detailsEditorContainer); const masterEditor = this.doCreateEditor(newInput.master, this.masterEditorContainer); @@ -198,7 +198,7 @@ export class SideBySideEditor extends BaseEditor { return editor; } - private async onEditorsCreated(details: BaseEditor, master: BaseEditor, detailsInput: EditorInput, masterInput: EditorInput, options: EditorOptions, token: CancellationToken): Promise { + private async onEditorsCreated(details: BaseEditor, master: BaseEditor, detailsInput: EditorInput, masterInput: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { this.detailsEditor = details; this.masterEditor = master; @@ -210,7 +210,7 @@ export class SideBySideEditor extends BaseEditor { this.onDidCreateEditors.fire(undefined); await Promise.all([ - this.detailsEditor.setInput(detailsInput, null, token), + this.detailsEditor.setInput(detailsInput, undefined, token), this.masterEditor.setInput(masterInput, options, token)] ); } diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index ecc9b704d3..048d6eb3ac 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import * as objects from 'vs/base/common/objects'; -import * as types from 'vs/base/common/types'; +import { isFunction, isObject, isArray } from 'vs/base/common/types'; import { IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { IDiffEditorOptions, IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BaseTextEditor, IEditorConfiguration } from 'vs/workbench/browser/parts/editor/textEditor'; @@ -31,7 +31,8 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { CancellationToken } from 'vs/base/common/cancellation'; import { EditorMemento } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import { EditorActivation } from 'vs/platform/editor/common/editor'; +import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; /** * The text editor that leverages the diff text editor for the editing experience. @@ -40,7 +41,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { static readonly ID = TEXT_DIFF_EDITOR_ID; - private diffNavigator: DiffNavigator; + private diffNavigator: DiffNavigator | undefined; private readonly diffNavigatorDisposables = this._register(new DisposableStore()); private reverseColor: boolean; // {{SQL CARBON EDIT}} add property @@ -54,7 +55,8 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { @IThemeService themeService: IThemeService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, - @IWindowService windowService: IWindowService + @IWindowService windowService: IWindowService, + @IClipboardService private _clipboardService: IClipboardService, ) { super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, windowService); } @@ -63,7 +65,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { return new EditorMemento(this.getId(), key, Object.create(null), limit, editorGroupService); // do not persist in storage as diff editors are never persisted } - getTitle(): string | null { + getTitle(): string | undefined { if (this.input) { return this.input.getName(); } @@ -77,15 +79,13 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { } createEditorControl(parent: HTMLElement, configuration: ICodeEditorOptions): IDiffEditor { - // {{SQL CARBON EDIT}} - if (this.reverseColor) { + if (this.reverseColor) { // {{SQL CARBON EDIT}} (configuration as IDiffEditorOptions).reverse = true; } - - return this.instantiationService.createInstance(DiffEditorWidget, parent, configuration); + return this.instantiationService.createInstance(DiffEditorWidget, parent, configuration, this._clipboardService); } - async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { + async setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { // Dispose previous diff navigator this.diffNavigatorDisposables.clear(); @@ -116,7 +116,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { // Apply Options from TextOptions let optionsGotApplied = false; - if (options && types.isFunction((options).apply)) { + if (options && isFunction((options).apply)) { optionsGotApplied = (options).apply(diffEditor, ScrollType.Immediate); } @@ -145,9 +145,9 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { } } - setOptions(options: EditorOptions): void { + setOptions(options: EditorOptions | undefined): void { const textOptions = options; - if (textOptions && types.isFunction(textOptions.apply)) { + if (textOptions && isFunction(textOptions.apply)) { textOptions.apply(this.getControl(), ScrollType.Smooth); } } @@ -168,7 +168,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { return false; } - private openAsBinary(input: EditorInput, options: EditorOptions): boolean { + private openAsBinary(input: EditorInput, options: EditorOptions | undefined): boolean { if (input instanceof DiffEditorInput) { const originalInput = input.originalInput; const modifiedInput = input.modifiedInput; @@ -189,7 +189,12 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { // because we are triggering another openEditor() call // and do not control the initial intent that resulted // in us now opening as binary. - options.overwrite({ activation: EditorActivation.PRESERVE }); + const preservingOptions: IEditorOptions = { activation: EditorActivation.PRESERVE }; + if (options) { + options.overwrite(preservingOptions); + } else { + options = EditorOptions.create(preservingOptions); + } this.editorService.openEditor(binaryDiffInput, options, this.group); @@ -203,7 +208,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { const editorConfiguration = super.computeConfiguration(configuration); // Handle diff editor specially by merging in diffEditor configuration - if (types.isObject(configuration.diffEditor)) { + if (isObject(configuration.diffEditor)) { objects.mixin(editorConfiguration, configuration.diffEditor); } @@ -245,7 +250,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { private isFileBinaryError(error: Error[]): boolean; private isFileBinaryError(error: Error): boolean; private isFileBinaryError(error: Error | Error[]): boolean { - if (types.isArray(error)) { + if (isArray(error)) { const errors = error; return errors.some(e => this.isFileBinaryError(e)); @@ -269,7 +274,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { super.clearInput(); } - getDiffNavigator(): DiffNavigator { + getDiffNavigator(): DiffNavigator | undefined { return this.diffNavigator; } @@ -281,7 +286,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { return super.loadTextEditorViewState(resource) as IDiffEditorViewState; // overridden for text diff editor support } - private saveTextDiffEditorViewState(input: EditorInput | null): void { + private saveTextDiffEditorViewState(input: EditorInput | undefined): void { if (!(input instanceof DiffEditorInput)) { return; // only supported for diff editor inputs } diff --git a/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts index 3fe55be0bb..0a52a4fbec 100644 --- a/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -39,7 +39,7 @@ export interface IEditorConfiguration { export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { private editorControl: IEditor; private _editorContainer: HTMLElement; - private hasPendingConfigurationChange: boolean; + private hasPendingConfigurationChange: boolean | undefined; private lastAppliedEditorOptions?: IEditorOptions; private editorMemento: IEditorMemento; @@ -191,7 +191,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { return this.instantiationService.createInstance(CodeEditorWidget, parent, configuration, {}); } - async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { + async setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { await super.setInput(input, options, token); // Update editor options after having set the input. We do this because there can be @@ -200,7 +200,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { this._editorContainer.setAttribute('aria-label', this.computeAriaLabel()); } - protected setEditorVisible(visible: boolean, group: IEditorGroup): void { + protected setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void { // Pass on to Editor if (visible) { diff --git a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts index 9110ced6a3..2ff5fdb9d1 100644 --- a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts @@ -46,7 +46,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor { super(id, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, windowService); } - getTitle(): string | null { + getTitle(): string | undefined { if (this.input) { return this.input.getName(); } @@ -54,7 +54,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor { return nls.localize('textEditor', "Text Editor"); } - async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { + async setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { // Remember view settings if input changes this.saveTextResourceEditorViewState(this.input); @@ -100,7 +100,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor { } } - setOptions(options: EditorOptions): void { + setOptions(options: EditorOptions | undefined): void { const textOptions = options; if (textOptions && types.isFunction(textOptions.apply)) { textOptions.apply(this.getControl(), ScrollType.Smooth); @@ -164,7 +164,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor { super.saveState(); } - private saveTextResourceEditorViewState(input: EditorInput | null): void { + private saveTextResourceEditorViewState(input: EditorInput | undefined): void { if (!(input instanceof UntitledEditorInput) && !(input instanceof ResourceEditorInput)) { return; // only enabled for untitled and resource inputs } diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index fe91b4b94f..a72d7c7262 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -57,7 +57,7 @@ export abstract class TitleControl extends Themable { private currentPrimaryEditorActionIds: string[] = []; private currentSecondaryEditorActionIds: string[] = []; - protected editorActionsToolbar: ToolBar; + private editorActionsToolbar: ToolBar; private resourceContext: ResourceContextKey; private editorPinnedContext: IContextKey; @@ -275,7 +275,7 @@ export abstract class TitleControl extends Themable { label = localize('draggedEditorGroup', "{0} (+{1})", label, this.group.count - 1); } - applyDragImage(e, label, 'monaco-editor-group-drag-image'); + applyDragImage(e, withUndefinedAsNull(label), 'monaco-editor-group-drag-image'); } })); diff --git a/src/vs/workbench/browser/parts/notifications/notificationsList.ts b/src/vs/workbench/browser/parts/notifications/notificationsList.ts index 6142b9ca2f..90198784a5 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsList.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsList.ts @@ -21,7 +21,7 @@ export class NotificationsList extends Themable { private listContainer: HTMLElement; private list: WorkbenchList; private viewModel: INotificationViewItem[]; - private isVisible: boolean; + private isVisible: boolean | undefined; constructor( private container: HTMLElement, @@ -72,6 +72,7 @@ export class NotificationsList extends Themable { // List this.list = this._register(this.instantiationService.createInstance( WorkbenchList, + 'NotificationsList', this.listContainer, new NotificationsListDelegate(this.listContainer), [renderer], diff --git a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts index 69c34230a2..1ddb77eae9 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts @@ -54,7 +54,7 @@ export class NotificationsToasts extends Themable { private notificationsToastsContainer: HTMLElement; private workbenchDimensions: Dimension; - private isNotificationsCenterVisible: boolean; + private isNotificationsCenterVisible: boolean | undefined; private mapNotificationToToast: Map; private notificationsToastsVisibleContextKey: IContextKey; @@ -236,12 +236,11 @@ export class NotificationsToasts extends Themable { purgeTimeoutHandle = setTimeout(() => { - // If the notification is sticky or prompting and the window does not have - // focus, we wait for the window to gain focus again before triggering - // the timeout again. This prevents an issue where focussing the window - // could immediately hide the notification because the timeout was triggered - // again. - if ((item.sticky || item.hasPrompt()) && !this.windowService.hasFocus) { + // If the window does not have focus, we wait for the window to gain focus + // again before triggering the timeout again. This prevents an issue where + // focussing the window could immediately hide the notification because the + // timeout was triggered again. + if (!this.windowService.hasFocus) { if (!listener) { listener = this.windowService.onDidChangeFocus(focus => { if (focus) { diff --git a/src/vs/workbench/browser/parts/panel/media/panelpart.css b/src/vs/workbench/browser/parts/panel/media/panelpart.css index d09c121965..3538f3ba12 100644 --- a/src/vs/workbench/browser/parts/panel/media/panelpart.css +++ b/src/vs/workbench/browser/parts/panel/media/panelpart.css @@ -13,7 +13,6 @@ } .monaco-workbench .part.panel .title { - padding-right: 0px; height: 35px; display: flex; flex-direction: row; diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index 210bcbeba8..4c5adad979 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -17,7 +17,7 @@ import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ClosePanelAction, TogglePanelPositionAction, PanelActivityAction, ToggleMaximizedPanelAction, TogglePanelAction } from 'vs/workbench/browser/parts/panel/panelActions'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_DRAG_AND_DROP_BACKGROUND, PANEL_INPUT_BORDER } from 'vs/workbench/common/theme'; @@ -48,7 +48,7 @@ export class PanelPart extends CompositePart implements IPanelService { private static readonly PINNED_PANELS = 'workbench.panel.pinnedPanels'; private static readonly MIN_COMPOSITE_BAR_WIDTH = 50; - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; //#region IView diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts index 309701dcbe..cc2189f738 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -8,7 +8,7 @@ import { Component } from 'vs/workbench/common/component'; import { IQuickInputService, IQuickPickItem, IPickOptions, IInputOptions, IQuickNavigateConfiguration, IQuickPick, IQuickInput, IQuickInputButton, IInputBox, IQuickPickItemButtonEvent, QuickPickInput, IQuickPickSeparator, IKeyMods } from 'vs/platform/quickinput/common/quickInput'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import * as dom from 'vs/base/browser/dom'; -import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { contrastBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { QUICK_INPUT_BACKGROUND, QUICK_INPUT_FOREGROUND } from 'vs/workbench/common/theme'; @@ -44,6 +44,7 @@ import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; const $ = dom.$; @@ -51,8 +52,8 @@ type Writeable = { -readonly [P in keyof T]: T[P] }; const backButton = { iconPath: { - dark: URI.parse(require.toUrl('vs/workbench/browser/parts/quickinput/media/arrow-left-dark.svg')), - light: URI.parse(require.toUrl('vs/workbench/browser/parts/quickinput/media/arrow-left-light.svg')) + dark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/quickinput/media/arrow-left-dark.svg')), + light: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/quickinput/media/arrow-left-light.svg')) }, tooltip: localize('quickInput.back', "Back"), handle: -1 // TODO @@ -880,7 +881,7 @@ class InputBox extends QuickInput implements IInputBox { export class QuickInputService extends Component implements IQuickInputService { - public _serviceBrand!: ServiceIdentifier; + public _serviceBrand: undefined; private static readonly ID = 'workbench.component.quickinput'; private static readonly MAX_WIDTH = 600; // Max total width of quick open widget diff --git a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts index 1f31fadcde..f47055bdf4 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts @@ -246,7 +246,7 @@ export class QuickInputList { this.id = id; this.container = dom.append(this.parent, $('.quick-input-list')); const delegate = new ListElementDelegate(); - this.list = this.instantiationService.createInstance(WorkbenchList, this.container, delegate, [new ListElementRenderer()], { + this.list = this.instantiationService.createInstance(WorkbenchList, 'QuickInput', this.container, delegate, [new ListElementRenderer()], { identityProvider: { getId: element => element.saneLabel }, openController: { shouldOpen: () => false }, // Workaround #58124 setRowLineHeight: false, diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 54c7650ce2..84c4ed7c79 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -30,7 +30,7 @@ import { QuickOpenHandler, QuickOpenHandlerDescriptor, IQuickOpenRegistry, Exten import * as errors from 'vs/base/common/errors'; import { IQuickOpenService, IShowOptions } from 'vs/platform/quickOpen/common/quickOpen'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -61,7 +61,7 @@ export class QuickOpenController extends Component implements IQuickOpenService private static readonly MAX_SHORT_RESPONSE_TIME = 500; private static readonly ID = 'workbench.component.quickopen'; - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private readonly _onShow: Emitter = this._register(new Emitter()); readonly onShow: Event = this._onShow.event; @@ -183,10 +183,10 @@ export class QuickOpenController extends Component implements IQuickOpenService onHide: (reason) => this.handleOnHide(reason), onFocusLost: () => !this.closeOnFocusLost }, { - inputPlaceHolder: this.hasHandler(HELP_PREFIX) ? nls.localize('quickOpenInput', "Type '?' to get help on the actions you can take from here") : '', - keyboardSupport: false, - treeCreator: (container, config, opts) => this.instantiationService.createInstance(WorkbenchTree, container, config, opts) - } + inputPlaceHolder: this.hasHandler(HELP_PREFIX) ? nls.localize('quickOpenInput', "Type '?' to get help on the actions you can take from here") : '', + keyboardSupport: false, + treeCreator: (container, config, opts) => this.instantiationService.createInstance(WorkbenchTree, container, config, opts) + } )); this._register(attachQuickOpenStyler(this.quickOpenWidget, this.themeService, { background: QUICK_INPUT_BACKGROUND, foreground: QUICK_INPUT_FOREGROUND })); diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index 9f8e0a7df9..88ce5065b5 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -19,7 +19,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; -import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Event, Emitter } from 'vs/base/common/event'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; @@ -35,7 +35,7 @@ import { LayoutPriority } from 'vs/base/browser/ui/grid/grid'; export class SidebarPart extends CompositePart implements IViewletService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; static readonly activeViewletSettingsKey = 'workbench.sidebar.activeviewletid'; diff --git a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css index da22288d23..b41332dce7 100644 --- a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css +++ b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css @@ -12,6 +12,18 @@ display: flex; } +.monaco-workbench .part.statusbar.status-border-top::after { + content: ''; + position: absolute; + top: 0; + left: 0; + z-index: 5; + pointer-events: none; + background-color: var(--status-border-top-color); + width: 100%; + height: 1px; +} + .monaco-workbench .part.statusbar > .left-items, .monaco-workbench .part.statusbar > .right-items { display: flex; diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index 6b6ed53e9f..317ed6fdea 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -11,7 +11,7 @@ import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Part } from 'vs/workbench/browser/part'; -import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -57,7 +57,7 @@ class StatusbarViewModel extends Disposable { private readonly _entries: IStatusbarViewModelEntry[] = []; get entries(): IStatusbarViewModelEntry[] { return this._entries; } - private hidden: Set; + private hidden!: Set; constructor(private storageService: IStorageService) { super(); @@ -323,7 +323,7 @@ class HideStatusbarEntryAction extends Action { export class StatusbarPart extends Part implements IStatusbarService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; //#region IView @@ -334,14 +334,14 @@ export class StatusbarPart extends Part implements IStatusbarService { //#endregion - private styleElement: HTMLStyleElement; + private styleElement!: HTMLStyleElement; private pendingEntries: IPendingStatusbarEntry[] = []; private readonly viewModel: StatusbarViewModel; - private leftItemsContainer: HTMLElement; - private rightItemsContainer: HTMLElement; + private leftItemsContainer!: HTMLElement; + private rightItemsContainer!: HTMLElement; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -580,9 +580,13 @@ export class StatusbarPart extends Part implements IStatusbarService { // Border color const borderColor = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BORDER : STATUS_BAR_NO_FOLDER_BORDER) || this.getColor(contrastBorder); - container.style.borderTopWidth = borderColor ? '1px' : null; - container.style.borderTopStyle = borderColor ? 'solid' : null; - container.style.borderTopColor = borderColor; + if (borderColor) { + addClass(container, 'status-border-top'); + container.style.setProperty('--status-border-top-color', borderColor.toString()); + } else { + removeClass(container, 'status-border-top'); + container.style.removeProperty('--status-border-top-color'); + } // Notification Beak if (!this.styleElement) { @@ -623,10 +627,10 @@ export class StatusbarPart extends Part implements IStatusbarService { } class StatusbarEntryItem extends Disposable { - private entry: IStatusbarEntry; + private entry!: IStatusbarEntry; - private labelContainer: HTMLElement; - private label: OcticonLabel; + private labelContainer!: HTMLElement; + private label!: OcticonLabel; private readonly foregroundListener = this._register(new MutableDisposable()); private readonly backgroundListener = this._register(new MutableDisposable()); diff --git a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts index a72b0e3891..29158c4651 100644 --- a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -254,6 +254,7 @@ export class CustomMenubarControl extends MenubarControl { private menubar: MenuBar; private container: HTMLElement; private alwaysOnMnemonics: boolean; + private focusInsideMenubar: boolean; private readonly _onVisibilityChange: Emitter; private readonly _onFocusStateChange: Emitter; @@ -469,11 +470,11 @@ export class CustomMenubarControl extends MenubarControl { if (firstTime) { this.menubar = this._register(new MenuBar( this.container, { - enableMnemonics: this.currentEnableMenuBarMnemonics, - disableAltFocus: this.currentDisableMenuBarAltFocus, - visibility: this.currentMenubarVisibility, - getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), - } + enableMnemonics: this.currentEnableMenuBarMnemonics, + disableAltFocus: this.currentDisableMenuBarAltFocus, + visibility: this.currentMenubarVisibility, + getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), + } )); this.accessibilityService.alwaysUnderlineAccessKeys().then(val => { @@ -481,9 +482,27 @@ export class CustomMenubarControl extends MenubarControl { this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics }); }); - this._register(this.menubar.onFocusStateChange(e => this._onFocusStateChange.fire(e))); + this._register(this.menubar.onFocusStateChange(focused => { + this._onFocusStateChange.fire(focused); + + // When the menubar loses focus, update it to clear any pending updates + if (!focused) { + this.updateMenubar(); + this.focusInsideMenubar = false; + } + })); + this._register(this.menubar.onVisibilityChange(e => this._onVisibilityChange.fire(e))); + // Before we focus the menubar, stop updates to it so that focus-related context keys will work + this._register(DOM.addDisposableListener(this.container, DOM.EventType.FOCUS_IN, () => { + this.focusInsideMenubar = true; + })); + + this._register(DOM.addDisposableListener(this.container, DOM.EventType.FOCUS_OUT, () => { + this.focusInsideMenubar = false; + })); + this._register(attachMenuStyler(this.menubar, this.themeService)); } else { this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics }); @@ -503,9 +522,11 @@ export class CustomMenubarControl extends MenubarControl { this.menus[action.item.submenu] = this.menuService.createMenu(action.item.submenu, this.contextKeyService); const submenu = this.menus[action.item.submenu]; this._register(submenu!.onDidChange(() => { - const actions: IAction[] = []; - updateActions(menu, actions, topLevelTitle); - this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[topLevelTitle]) }); + if (!this.focusInsideMenubar) { + const actions: IAction[] = []; + updateActions(menu, actions, topLevelTitle); + this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[topLevelTitle]) }); + } }, this)); } @@ -529,9 +550,11 @@ export class CustomMenubarControl extends MenubarControl { const menu = this.menus[title]; if (firstTime && menu) { this._register(menu.onDidChange(() => { - const actions: IAction[] = []; - updateActions(menu, actions, title); - this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) }); + if (!this.focusInsideMenubar) { + const actions: IAction[] = []; + updateActions(menu, actions, title); + this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) }); + } })); } diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 43de53c166..5d1783a8e8 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -28,7 +28,7 @@ import { Color } from 'vs/base/common/color'; import { trim } from 'vs/base/common/strings'; import { EventType, EventHelper, Dimension, isAncestor, hide, show, removeClass, addClass, append, $, addDisposableListener, runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; import { CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menubarControl'; -import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { template, getBaseLabel } from 'vs/base/common/labels'; import { ILabelService } from 'vs/platform/label/common/label'; import { Event, Emitter } from 'vs/base/common/event'; @@ -58,7 +58,7 @@ export class TitlebarPart extends Part implements ITitleService { private _onMenubarVisibilityChange = this._register(new Emitter()); readonly onMenubarVisibilityChange: Event = this._onMenubarVisibilityChange.event; - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private title: HTMLElement; private dragRegion: HTMLElement; @@ -554,7 +554,7 @@ export class TitlebarPart extends Part implements ITitleService { rightMarker < (this.element.clientWidth + this.title.clientWidth) / 2) { this.title.style.position = null; this.title.style.left = null; - this.title.style.transform = null; + this.title.style.transform = ''; return; } } diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index 28aa41a1d5..b95a18365c 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -58,6 +58,7 @@ export class CustomTreeViewPanel extends ViewletPanel { const { treeView } = (Registry.as(Extensions.ViewsRegistry).getView(options.id)); this.treeView = treeView; this._register(this.treeView.onDidChangeActions(() => this.updateActions(), this)); + this._register(this.treeView.onDidChangeTitle((newTitle) => this.updateTitle(newTitle))); this._register(toDisposable(() => this.treeView.setVisibility(false))); this._register(this.onDidChangeBodyVisibility(() => this.updateTreeVisibility())); this.updateTreeVisibility(); @@ -190,9 +191,12 @@ export class CustomTreeView extends Disposable implements ITreeView { private readonly _onDidChangeActions: Emitter = this._register(new Emitter()); readonly onDidChangeActions: Event = this._onDidChangeActions.event; + private readonly _onDidChangeTitle: Emitter = this._register(new Emitter()); + readonly onDidChangeTitle: Event = this._onDidChangeTitle.event; + constructor( private id: string, - private title: string, + private _title: string, private viewContainer: ViewContainer, @IExtensionService private readonly extensionService: IExtensionService, @IWorkbenchThemeService private readonly themeService: IWorkbenchThemeService, @@ -201,7 +205,8 @@ export class CustomTreeView extends Disposable implements ITreeView { @IConfigurationService private readonly configurationService: IConfigurationService, @IProgressService private readonly progressService: IProgressService, @IContextMenuService private readonly contextMenuService: IContextMenuService, - @IKeybindingService private readonly keybindingService: IKeybindingService + @IKeybindingService private readonly keybindingService: IKeybindingService, + @INotificationService private readonly notificationService: INotificationService ) { super(); this.root = new Root(); @@ -228,6 +233,10 @@ export class CustomTreeView extends Disposable implements ITreeView { } set dataProvider(dataProvider: ITreeViewDataProvider | undefined) { + if (this.tree === undefined) { + this.createTree(); + } + if (dataProvider) { this._dataProvider = new class implements ITreeViewDataProvider { async getChildren(node: ITreeItem): Promise { @@ -257,6 +266,15 @@ export class CustomTreeView extends Disposable implements ITreeView { this.updateMessage(); } + get title(): string { + return this._title; + } + + set title(name: string) { + this._title = name; + this._onDidChangeTitle.fire(this._title); + } + get canSelectMany(): boolean { return this._canSelectMany; } @@ -366,28 +384,28 @@ export class CustomTreeView extends Disposable implements ITreeView { const aligner = new Aligner(this.themeService); const renderer = this.instantiationService.createInstance(TreeRenderer, this.id, treeMenus, this.treeLabels, actionViewItemProvider, aligner); - this.tree = this._register(this.instantiationService.createInstance(WorkbenchAsyncDataTree, this.treeContainer, new CustomTreeDelegate(), [renderer], + this.tree = this._register(this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'CustomView', this.treeContainer, new CustomTreeDelegate(), [renderer], dataSource, { - identityProvider: new CustomViewIdentityProvider(), - accessibilityProvider: { - getAriaLabel(element: ITreeItem): string { - return element.label ? element.label.label : ''; - } - }, - ariaLabel: this.title, - keyboardNavigationLabelProvider: { - getKeyboardNavigationLabel: (item: ITreeItem) => { - return item.label ? item.label.label : (item.resourceUri ? basename(URI.revive(item.resourceUri)) : undefined); - } - }, - expandOnlyOnTwistieClick: (e: ITreeItem) => !!e.command, - collapseByDefault: (e: ITreeItem): boolean => { - return e.collapsibleState !== TreeItemCollapsibleState.Expanded; - }, - multipleSelectionSupport: this.canSelectMany, - }) as WorkbenchAsyncDataTree); + identityProvider: new CustomViewIdentityProvider(), + accessibilityProvider: { + getAriaLabel(element: ITreeItem): string { + return element.tooltip ? element.tooltip : element.label ? element.label.label : ''; + } + }, + ariaLabel: this._title, + keyboardNavigationLabelProvider: { + getKeyboardNavigationLabel: (item: ITreeItem) => { + return item.label ? item.label.label : (item.resourceUri ? basename(URI.revive(item.resourceUri)) : undefined); + } + }, + expandOnlyOnTwistieClick: (e: ITreeItem) => !!e.command, + collapseByDefault: (e: ITreeItem): boolean => { + return e.collapsibleState !== TreeItemCollapsibleState.Expanded; + }, + multipleSelectionSupport: this.canSelectMany, + }) as WorkbenchAsyncDataTree); aligner.tree = this.tree; - const actionRunner = new MultipleSelectionActionRunner(() => this.tree!.getSelection()); + const actionRunner = new MultipleSelectionActionRunner(this.notificationService, () => this.tree!.getSelection()); renderer.actionRunner = actionRunner; this.tree.contextKeyService.createKey(this.id, true); @@ -578,7 +596,6 @@ export class CustomTreeView extends Disposable implements ITreeView { private activate() { if (!this.activated) { - this.createTree(); this.progressService.withProgress({ location: this.viewContainer.id }, () => this.extensionService.activateByEvent(`onView:${this.id}`)) .then(() => timeout(2000)) .then(() => { @@ -593,16 +610,8 @@ export class CustomTreeView extends Disposable implements ITreeView { const tree = this.tree; if (tree) { this.refreshing = true; - const parents: Set = new Set(); - elements.forEach(element => { - if (element !== this.root) { - const parent = tree.getParentElement(element); - parents.add(parent); - } else { - parents.add(element); - } - }); - await Promise.all(Array.from(parents.values()).map(element => tree.updateChildren(element, true))); + await Promise.all(elements.map(element => tree.updateChildren(element, true))); + elements.map(element => tree.rerender(element)); this.refreshing = false; this.updateContentAreas(); if (this.focused) { @@ -845,22 +854,32 @@ class Aligner extends Disposable { class MultipleSelectionActionRunner extends ActionRunner { - constructor(private getSelectedResources: (() => ITreeItem[])) { + constructor(notificationService: INotificationService, private getSelectedResources: (() => ITreeItem[])) { super(); + this._register(this.onDidRun(e => { + if (e.error) { + notificationService.error(localize('command-error', 'Error running command {1}: {0}. This is likely caused by the extension that contributes {1}.', e.error.message, e.action.id)); + } + })); } runAction(action: IAction, context: TreeViewItemHandleArg): Promise { const selection = this.getSelectedResources(); let selectionHandleArgs: TreeViewItemHandleArg[] | undefined = undefined; + let actionInSelected: boolean = false; if (selection.length > 1) { - selectionHandleArgs = []; - selection.forEach(selected => { - if (selected.handle !== context.$treeItemHandle) { - selectionHandleArgs!.push({ $treeViewId: context.$treeViewId, $treeItemHandle: selected.handle }); + selectionHandleArgs = selection.map(selected => { + if (selected.handle === context.$treeItemHandle) { + actionInSelected = true; } + return { $treeViewId: context.$treeViewId, $treeItemHandle: selected.handle }; }); } + if (!actionInSelected) { + selectionHandleArgs = undefined; + } + return action.run(...[context, selectionHandleArgs]); } } diff --git a/src/vs/workbench/browser/parts/views/views.ts b/src/vs/workbench/browser/parts/views/views.ts index edffcc7172..a1677c2483 100644 --- a/src/vs/workbench/browser/parts/views/views.ts +++ b/src/vs/workbench/browser/parts/views/views.ts @@ -20,7 +20,6 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { values } from 'vs/base/common/map'; import { IFileIconTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { toggleClass, addClass } from 'vs/base/browser/dom'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; function filterViewRegisterEvent(container: ViewContainer, event: Event<{ viewContainer: ViewContainer, views: IViewDescriptor[] }>): Event { @@ -382,7 +381,7 @@ export class ContributableViewsModel extends Disposable { return 0; } - return (this.getViewOrder(a) - this.getViewOrder(b)) || this.getGroupOrderResult(a, b) || (a.id < b.id ? -1 : 1); + return (this.getViewOrder(a) - this.getViewOrder(b)) || this.getGroupOrderResult(a, b); } private getGroupOrderResult(a: IViewDescriptor, b: IViewDescriptor) { @@ -434,7 +433,7 @@ export class ContributableViewsModel extends Disposable { const splices = sortedDiff( this.viewDescriptors, viewDescriptors, - this.compareViewDescriptors.bind(this) + (a, b) => a.id === b.id ? 0 : a.id < b.id ? -1 : 1 ).reverse(); const toRemove: { index: number, viewDescriptor: IViewDescriptor }[] = []; @@ -522,9 +521,7 @@ export class PersistentContributableViewsModel extends ContributableViewsModel { } private saveWorkspaceViewsStates(): void { - const storedViewsStates: { [id: string]: IStoredWorkspaceViewState } = {}; - - let hasState = false; + const storedViewsStates: { [id: string]: IStoredWorkspaceViewState } = JSON.parse(this.storageService.get(this.workspaceViewsStateStorageId, StorageScope.WORKSPACE, '{}')); for (const viewDescriptor of this.viewDescriptors) { const viewState = this.viewStates.get(viewDescriptor.id); if (viewState) { @@ -534,11 +531,10 @@ export class PersistentContributableViewsModel extends ContributableViewsModel { size: viewState.size, order: viewDescriptor.workspace && viewState ? viewState.order : undefined }; - hasState = true; } } - if (hasState) { + if (Object.keys(storedViewsStates).length > 0) { this.storageService.store(this.workspaceViewsStateStorageId, JSON.stringify(storedViewsStates), StorageScope.WORKSPACE); } else { this.storageService.remove(this.workspaceViewsStateStorageId, StorageScope.WORKSPACE); @@ -638,7 +634,7 @@ export class PersistentContributableViewsModel extends ContributableViewsModel { export class ViewsService extends Disposable implements IViewsService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private readonly viewDescriptorCollections: Map; private readonly viewDisposable: Map; diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index 1091615533..7648dacbe1 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -39,7 +39,7 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView private readonly viewletState: MementoObject; private didLayout = false; - private dimension: DOM.Dimension; + private dimension: DOM.Dimension | undefined; private areExtensionsReady: boolean = false; private readonly visibleViewsCountFromCache: number | undefined; diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index db61d8f790..13c9d55d50 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -13,7 +13,8 @@ import { Workbench } from 'vs/workbench/browser/workbench'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } from 'vs/platform/remote/common/remoteAgentFileSystemChannel'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IProductService, IProductConfiguration } from 'vs/platform/product/common/product'; +import { IProductService } from 'vs/platform/product/common/product'; +import product from 'vs/platform/product/browser/product'; import { RemoteAgentService } from 'vs/workbench/services/remote/browser/remoteAgentServiceImpl'; import { RemoteAuthorityResolverService } from 'vs/platform/remote/browser/remoteAuthorityResolverService'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; @@ -121,7 +122,7 @@ class CodeRendererMain extends Disposable { // Log const logsPath = URI.file(toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')).with({ scheme: 'vscode-log' }); - const logService = new BufferLogService(); + const logService = new BufferLogService(this.configuration.logLevel); serviceCollection.set(ILogService, logService); const payload = this.resolveWorkspaceInitializationPayload(); @@ -131,11 +132,17 @@ class CodeRendererMain extends Disposable { serviceCollection.set(IWorkbenchEnvironmentService, environmentService); // Product - const productService = this.createProductService(); + const productService = { + _serviceBrand: undefined, + ...{ + ...product, // dev or built time config + ...{ urlProtocol: '' } // web related overrides from us + } + }; serviceCollection.set(IProductService, productService); // Remote - const remoteAuthorityResolverService = new RemoteAuthorityResolverService(); + const remoteAuthorityResolverService = new RemoteAuthorityResolverService(this.configuration.resourceUriProvider); serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService); // Signing @@ -220,18 +227,6 @@ class CodeRendererMain extends Disposable { fileService.registerProvider(Schemas.userData, this.configuration.userDataProvider); } - private createProductService(): IProductService { - const productConfiguration = { - ...this.configuration.productConfiguration ? this.configuration.productConfiguration : { - version: '1.38.0-unknown', - nameLong: 'Unknown', - extensionAllowedProposedApi: [], - }, ...{ urlProtocol: '' } - } as IProductConfiguration; - - return { _serviceBrand: undefined, ...productConfiguration }; - } - private async createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: IFileService, logService: ILogService): Promise { const storageService = new BrowserStorageService(environmentService, fileService); diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts index 9341fb5860..bbb8eebb02 100644 --- a/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/browser/web.simpleservices.ts @@ -10,14 +10,11 @@ import { Event } from 'vs/base/common/event'; import { ILogService } from 'vs/platform/log/common/log'; import { Disposable } from 'vs/base/common/lifecycle'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IUpdateService, State } from 'vs/platform/update/common/update'; import { IWindowService, INativeOpenDialogOptions, IEnterWorkspaceResult, IURIToOpen, IMessageBoxResult, IWindowsService, IOpenSettings, IWindowSettings } from 'vs/platform/windows/common/windows'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceFolderCreationData, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { IRecentlyOpened, IRecent, isRecentFile, isRecentFolder } from 'vs/platform/history/common/history'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; -import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; -import { ITunnelService } from 'vs/platform/remote/common/tunnel'; -import { IWorkspaceContextService, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { addDisposableListener, EventType, windowOpenNoOpener } from 'vs/base/browser/dom'; import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService'; import { pathsToEditors } from 'vs/workbench/common/editor'; @@ -31,48 +28,12 @@ import { IProductService } from 'vs/platform/product/common/product'; import Severity from 'vs/base/common/severity'; import { localize } from 'vs/nls'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -// tslint:disable-next-line: import-patterns -import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/common/workspaceStats'; - -//#region Update - -export class SimpleUpdateService implements IUpdateService { - - _serviceBrand: any; - - onStateChange = Event.None; - state: State; - - checkForUpdates(context: any): Promise { - return Promise.resolve(undefined); - } - - downloadUpdate(): Promise { - return Promise.resolve(undefined); - } - - applyUpdate(): Promise { - return Promise.resolve(undefined); - } - - quitAndInstall(): Promise { - return Promise.resolve(undefined); - } - - isLatestVersion(): Promise { - return Promise.resolve(true); - } -} - -registerSingleton(IUpdateService, SimpleUpdateService); - -//#endregion //#region Window export class SimpleWindowService extends Disposable implements IWindowService { - _serviceBrand: any; + _serviceBrand: undefined; readonly onDidChangeFocus: Event = Event.None; readonly onDidChangeMaximize: Event = Event.None; @@ -360,7 +321,7 @@ registerSingleton(IWindowService, SimpleWindowService); //#region Window export class SimpleWindowsService implements IWindowsService { - _serviceBrand: any; + _serviceBrand: undefined; windowCount = 1; @@ -377,6 +338,7 @@ export class SimpleWindowsService implements IWindowsService { @IClipboardService private readonly clipboardService: IClipboardService ) { } + isFocused(_windowId: number): Promise { return Promise.resolve(true); } @@ -520,18 +482,9 @@ export class SimpleWindowsService implements IWindowsService { const f = args['folder-uri']; if (f) { - let u: URI | undefined; - if (Array.isArray(f)) { - if (f.length > 0) { - u = URI.parse(f[0]); - } - } else { - u = URI.parse(f); - } - if (u) { - gotFolder = true; - addQueryParameter('folder', u.path); - } + const u = URI.parse(f[0]); + gotFolder = true; + addQueryParameter('folder', u.path); } if (!gotFolder) { // request empty window @@ -540,17 +493,8 @@ export class SimpleWindowsService implements IWindowsService { const ep = args['extensionDevelopmentPath']; if (ep) { - let u: string | undefined; - if (Array.isArray(ep)) { - if (ep.length > 0) { - u = ep[0]; - } - } else { - u = ep; - } - if (u) { - addQueryParameter('edp', u); - } + let u = ep[0]; + addQueryParameter('edp', u); } const di = args['debugId']; @@ -613,7 +557,7 @@ export class SimpleWindowsService implements IWindowsService { } getActiveWindowId(): Promise { - return Promise.resolve(undefined); + return Promise.resolve(0); } // This needs to be handled from browser process to prevent @@ -650,9 +594,9 @@ export class SimpleWindowsService implements IWindowsService { navigator.userAgent ); - const result = await this.dialogService.show(Severity.Info, this.productService.nameLong, [localize('copy', "Copy"), localize('ok', "OK")], { detail }); + const { choice } = await this.dialogService.show(Severity.Info, this.productService.nameLong, [localize('copy', "Copy"), localize('ok', "OK")], { detail }); - if (result === 0) { + if (choice === 0) { this.clipboardService.writeText(detail); } } @@ -666,55 +610,11 @@ registerSingleton(IWindowsService, SimpleWindowsService); //#endregion -//#region Workspace Editing - -export class SimpleWorkspaceEditingService implements IWorkspaceEditingService { - - _serviceBrand: any; - - addFolders(folders: IWorkspaceFolderCreationData[], donotNotifyError?: boolean): Promise { - return Promise.resolve(undefined); - } - - removeFolders(folders: URI[], donotNotifyError?: boolean): Promise { - return Promise.resolve(undefined); - } - - updateFolders(index: number, deleteCount?: number, foldersToAdd?: IWorkspaceFolderCreationData[], donotNotifyError?: boolean): Promise { - return Promise.resolve(undefined); - } - - enterWorkspace(path: URI): Promise { - return Promise.resolve(undefined); - } - - createAndEnterWorkspace(folders: IWorkspaceFolderCreationData[], path?: URI): Promise { - return Promise.resolve(undefined); - } - - saveAndEnterWorkspace(path: URI): Promise { - return Promise.resolve(undefined); - } - - copyWorkspaceSettings(toWorkspace: IWorkspaceIdentifier): Promise { - return Promise.resolve(undefined); - } - - pickNewWorkspacePath(): Promise { - // @ts-ignore - return Promise.resolve(undefined); - } -} - -registerSingleton(IWorkspaceEditingService, SimpleWorkspaceEditingService, true); - -//#endregion - //#region Workspaces export class SimpleWorkspacesService implements IWorkspacesService { - _serviceBrand: any; + _serviceBrand: undefined; createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise { // @ts-ignore @@ -734,40 +634,3 @@ export class SimpleWorkspacesService implements IWorkspacesService { registerSingleton(IWorkspacesService, SimpleWorkspacesService); //#endregion - -//#region remote - -class SimpleTunnelService implements ITunnelService { - _serviceBrand: any; - openTunnel(remotePort: number) { - return undefined; - } -} - -registerSingleton(ITunnelService, SimpleTunnelService); - -//#endregion - -//#region workspace stats - -class SimpleWorkspaceStatsService implements IWorkspaceStatsService { - - _serviceBrand: any; - - getTags(): Promise { - return Promise.resolve({}); - } - - getTelemetryWorkspaceId(workspace: IWorkspace, state: WorkbenchState): string | undefined { - return undefined; - } - - getHashedRemotesFromUri(workspaceUri: URI, stripEndingDotGit?: boolean): Promise { - return Promise.resolve([]); - } - -} - -registerSingleton(IWorkspaceStatsService, SimpleWorkspaceStatsService); - -//#endregion diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index c31d189933..68492759aa 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -242,7 +242,7 @@ import { isMacintosh, isWindows, isLinux, isWeb } from 'vs/base/common/platform' }, 'workbench.octiconsUpdate.enabled': { 'type': 'boolean', - 'default': false, + 'default': true, 'description': nls.localize('workbench.octiconsUpdate.enabled', "Controls the visibility of the new Octicons style in the workbench.") } } diff --git a/src/vs/workbench/buildfile.js b/src/vs/workbench/buildfile.desktop.js similarity index 100% rename from src/vs/workbench/buildfile.js rename to src/vs/workbench/buildfile.desktop.js diff --git a/src/vs/workbench/buildfile.web.js b/src/vs/workbench/buildfile.web.js new file mode 100644 index 0000000000..df3dbd7c35 --- /dev/null +++ b/src/vs/workbench/buildfile.web.js @@ -0,0 +1,25 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +function createModuleDescription(name, exclude) { + const result = {}; + + let excludes = ['vs/css', 'vs/nls']; + result.name = name; + if (Array.isArray(exclude) && exclude.length > 0) { + excludes = excludes.concat(exclude); + } + result.exclude = excludes; + + return result; +} + +exports.collectModules = function () { + return [ + createModuleDescription('vs/workbench/contrib/output/common/outputLinkComputer', ['vs/base/common/worker/simpleWorker', 'vs/editor/common/services/editorSimpleWorker']), + createModuleDescription('vs/code/browser/workbench/workbench', ['vs/workbench/workbench.web.api']), + ]; +}; diff --git a/src/vs/workbench/common/composite.ts b/src/vs/workbench/common/composite.ts index a6e6a00c8a..12300b3977 100644 --- a/src/vs/workbench/common/composite.ts +++ b/src/vs/workbench/common/composite.ts @@ -15,7 +15,7 @@ export interface IComposite { /** * Returns the name of this composite to show in the title area. */ - getTitle(): string | null; + getTitle(): string | undefined; /** * Returns the primary actions of the composite. diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index a50d4605f1..f744db0eea 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -22,6 +22,7 @@ import { IPathData } from 'vs/platform/windows/common/windows'; import { coalesce } from 'vs/base/common/arrays'; export const ActiveEditorContext = new RawContextKey('activeEditor', null); +export const ActiveEditorIsSaveableContext = new RawContextKey('activeEditorIsSaveable', false); export const EditorsVisibleContext = new RawContextKey('editorIsOpen', false); export const EditorPinnedContext = new RawContextKey('editorPinned', false); export const EditorGroupActiveEditorDirtyContext = new RawContextKey('groupActiveEditorDirty', false); @@ -30,7 +31,7 @@ export const NoEditorsVisibleContext: ContextKeyExpr = EditorsVisibleContext.toN export const TextCompareEditorVisibleContext = new RawContextKey('textCompareEditorVisible', false); export const TextCompareEditorActiveContext = new RawContextKey('textCompareEditorActive', false); export const ActiveEditorGroupEmptyContext = new RawContextKey('activeEditorGroupEmpty', false); -export const ActiveEditorGroupIndexContext = new RawContextKey('activeEditorGroupIndex', -1); +export const ActiveEditorGroupIndexContext = new RawContextKey('activeEditorGroupIndex', 0); export const ActiveEditorGroupLastContext = new RawContextKey('activeEditorGroupLast', false); export const MultipleEditorGroupsContext = new RawContextKey('multipleEditorGroups', false); export const SingleEditorGroupsContext = MultipleEditorGroupsContext.toNegated(); @@ -53,12 +54,12 @@ export interface IEditor { /** * The assigned input of this editor. */ - input: IEditorInput | null; + input: IEditorInput | undefined; /** * The assigned options of this editor. */ - options: IEditorOptions | null; + options: IEditorOptions | undefined; /** * The assigned group this editor is showing in. @@ -292,7 +293,7 @@ export interface IEditorInput extends IDisposable { /** * Returns the display name of this input. */ - getName(): string | null; + getName(): string | undefined; /** * Returns the display description of this input. @@ -302,7 +303,7 @@ export interface IEditorInput extends IDisposable { /** * Returns the display title of this input. */ - getTitle(verbosity?: Verbosity): string | null; + getTitle(verbosity?: Verbosity): string | undefined; /** * Resolves the input. @@ -358,8 +359,8 @@ export abstract class EditorInput extends Disposable implements IEditorInput { * Returns the name of this input that can be shown to the user. Examples include showing the name of the input * above the editor area when the input is shown. */ - getName(): string | null { - return null; + getName(): string | undefined { + return undefined; } /** @@ -374,7 +375,7 @@ export abstract class EditorInput extends Disposable implements IEditorInput { * Returns the title of this input that can be shown to the user. Examples include showing the title of * the input above the editor area as hover over the input label. */ - getTitle(verbosity?: Verbosity): string | null { + getTitle(verbosity?: Verbosity): string | undefined { return this.getName(); } @@ -733,7 +734,8 @@ export class EditorOptions implements IEditorOptions { /** * This option is only relevant if an editor is opened into a group that is not active - * already and allows to control if the inactive group should become active or not. + * already and allows to control if the inactive group should become active, restored + * or preserved. * * By default, the editor group will become active unless `preserveFocus` or `inactive` * is specified. @@ -783,6 +785,11 @@ export class EditorOptions implements IEditorOptions { */ ignoreError: boolean | undefined; + /** + * Does not use editor overrides while opening the editor. + */ + ignoreOverrides: boolean | undefined; + /** * Overwrites option values from the provided bag. */ @@ -823,6 +830,10 @@ export class EditorOptions implements IEditorOptions { this.index = options.index; } + if (typeof options.ignoreOverrides === 'boolean') { + this.ignoreOverrides = options.ignoreOverrides; + } + return this; } } diff --git a/src/vs/workbench/common/editor/dataUriEditorInput.ts b/src/vs/workbench/common/editor/dataUriEditorInput.ts index 743a18166c..5ee0e17820 100644 --- a/src/vs/workbench/common/editor/dataUriEditorInput.ts +++ b/src/vs/workbench/common/editor/dataUriEditorInput.ts @@ -8,7 +8,6 @@ import { URI } from 'vs/base/common/uri'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; import { DataUri } from 'vs/base/common/resources'; -import { withUndefinedAsNull } from 'vs/base/common/types'; /** * An editor input to present data URIs in a binary editor. Data URIs have the form of: @@ -51,8 +50,8 @@ export class DataUriEditorInput extends EditorInput { return DataUriEditorInput.ID; } - getName(): string | null { - return withUndefinedAsNull(this.name); + getName(): string | undefined { + return this.name; } getDescription(): string | undefined { diff --git a/src/vs/workbench/common/editor/diffEditorInput.ts b/src/vs/workbench/common/editor/diffEditorInput.ts index f4bcc49378..29d71bfd3f 100644 --- a/src/vs/workbench/common/editor/diffEditorInput.ts +++ b/src/vs/workbench/common/editor/diffEditorInput.ts @@ -16,7 +16,7 @@ export class DiffEditorInput extends SideBySideEditorInput { static readonly ID = 'workbench.editors.diffEditorInput'; - private cachedModel: DiffEditorModel | null; + private cachedModel: DiffEditorModel | null = null; constructor(name: string, description: string | undefined, original: EditorInput, modified: EditorInput, private readonly forceOpenAsBinary?: boolean) { super(name, description, original, modified); @@ -86,4 +86,4 @@ export class DiffEditorInput extends SideBySideEditorInput { super.dispose(); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/common/editor/editorGroup.ts b/src/vs/workbench/common/editor/editorGroup.ts index d22e2474bd..e1c2d7a98a 100644 --- a/src/vs/workbench/common/editor/editorGroup.ts +++ b/src/vs/workbench/common/editor/editorGroup.ts @@ -96,16 +96,17 @@ export class EditorGroup extends Disposable { //#endregion private _id: GroupIdentifier; + get id(): GroupIdentifier { return this._id; } private editors: EditorInput[] = []; private mru: EditorInput[] = []; private mapResourceToEditorCount: ResourceMap = new ResourceMap(); - private preview: EditorInput | null; // editor in preview state - private active: EditorInput | null; // editor in active state + private preview: EditorInput | null = null; // editor in preview state + private active: EditorInput | null = null; // editor in active state - private editorOpenPositioning: 'left' | 'right' | 'first' | 'last'; - private focusRecentEditorAfterClose: boolean; + private editorOpenPositioning: ('left' | 'right' | 'first' | 'last') | undefined; + private focusRecentEditorAfterClose: boolean | undefined; constructor( labelOrSerializedGroup: ISerializedEditorGroup, @@ -115,7 +116,7 @@ export class EditorGroup extends Disposable { super(); if (isSerializedEditorGroup(labelOrSerializedGroup)) { - this.deserialize(labelOrSerializedGroup); + this._id = this.deserialize(labelOrSerializedGroup); } else { this._id = EditorGroup.IDS++; } @@ -133,10 +134,6 @@ export class EditorGroup extends Disposable { this.focusRecentEditorAfterClose = this.configurationService.getValue('workbench.editor.focusRecentEditorAfterClose'); } - get id(): GroupIdentifier { - return this._id; - } - get count(): number { return this.editors.length; } @@ -697,7 +694,7 @@ export class EditorGroup extends Disposable { }; } - private deserialize(data: ISerializedEditorGroup): void { + private deserialize(data: ISerializedEditorGroup): number { const registry = Registry.as(Extensions.EditorInputFactories); if (typeof data.id === 'number') { @@ -723,11 +720,16 @@ export class EditorGroup extends Disposable { return null; })); + this.mru = data.mru.map(i => this.editors[i]); + this.active = this.mru[0]; + if (typeof data.preview === 'number') { this.preview = this.editors[data.preview]; } + + return this._id; } // {{SQL CARBON EDIT}} diff --git a/src/vs/workbench/common/editor/resourceEditorInput.ts b/src/vs/workbench/common/editor/resourceEditorInput.ts index f8458d121e..6064e31cba 100644 --- a/src/vs/workbench/common/editor/resourceEditorInput.ts +++ b/src/vs/workbench/common/editor/resourceEditorInput.ts @@ -17,8 +17,8 @@ export class ResourceEditorInput extends EditorInput implements IModeSupport { static readonly ID: string = 'workbench.editors.resourceEditorInput'; - private cachedModel: ResourceEditorModel | null; - private modelReference: Promise> | null; + private cachedModel: ResourceEditorModel | null = null; + private modelReference: Promise> | null = null; constructor( private name: string, diff --git a/src/vs/workbench/common/editor/textDiffEditorModel.ts b/src/vs/workbench/common/editor/textDiffEditorModel.ts index b24a623d42..e49d9b5365 100644 --- a/src/vs/workbench/common/editor/textDiffEditorModel.ts +++ b/src/vs/workbench/common/editor/textDiffEditorModel.ts @@ -14,10 +14,10 @@ import { DiffEditorModel } from 'vs/workbench/common/editor/diffEditorModel'; */ export class TextDiffEditorModel extends DiffEditorModel { - protected readonly _originalModel: BaseTextEditorModel; - protected readonly _modifiedModel: BaseTextEditorModel; + protected readonly _originalModel!: BaseTextEditorModel | null; + protected readonly _modifiedModel!: BaseTextEditorModel | null; - private _textDiffEditorModel: IDiffEditorModel | null; + private _textDiffEditorModel: IDiffEditorModel | null = null; constructor(originalModel: BaseTextEditorModel, modifiedModel: BaseTextEditorModel) { super(originalModel, modifiedModel); @@ -25,11 +25,11 @@ export class TextDiffEditorModel extends DiffEditorModel { this.updateTextDiffEditorModel(); } - get originalModel(): BaseTextEditorModel { + get originalModel(): BaseTextEditorModel | null { return this._originalModel; } - get modifiedModel(): BaseTextEditorModel { + get modifiedModel(): BaseTextEditorModel | null { return this._modifiedModel; } @@ -42,7 +42,7 @@ export class TextDiffEditorModel extends DiffEditorModel { } private updateTextDiffEditorModel(): void { - if (this.originalModel.isResolved() && this.modifiedModel.isResolved()) { + if (this.originalModel && this.originalModel.isResolved() && this.modifiedModel && this.modifiedModel.isResolved()) { // Create new if (!this._textDiffEditorModel) { @@ -69,7 +69,7 @@ export class TextDiffEditorModel extends DiffEditorModel { } isReadonly(): boolean { - return this.modifiedModel.isReadonly(); + return !!this.modifiedModel && this.modifiedModel.isReadonly(); } dispose(): void { diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index 1a452f0e8a..d7229b2cc5 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -23,8 +23,8 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport static readonly ID: string = 'workbench.editors.untitledEditorInput'; - private cachedModel: UntitledEditorModel | null; - private modelResolve: Promise | null; + private cachedModel: UntitledEditorModel | null = null; + private modelResolve: Promise | null = null; private readonly _onDidModelChangeContent: Emitter = this._register(new Emitter()); readonly onDidModelChangeContent: Event = this._onDidModelChangeContent.event; @@ -107,7 +107,7 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport return this.labelService.getUriLabel(this.resource); } - getTitle(verbosity: Verbosity): string | null { + getTitle(verbosity: Verbosity): string | undefined { if (!this.hasAssociatedFilePath) { return this.getName(); } @@ -121,7 +121,7 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport return this.longTitle; } - return null; + return undefined; } isDirty(): boolean { diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index f2a0d28830..9d2f234903 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -383,13 +383,13 @@ export const EXTENSION_BADGE_REMOTE_BACKGROUND = registerColor('extensionBadge.r dark: ACTIVITY_BAR_BADGE_BACKGROUND, light: ACTIVITY_BAR_BADGE_BACKGROUND, hc: ACTIVITY_BAR_BADGE_BACKGROUND -}, nls.localize('extensionBadge.remoteBackground', "Background color for the remote badge in the extensions view")); +}, nls.localize('extensionBadge.remoteBackground', "Background color for the remote badge in the extensions view.")); export const EXTENSION_BADGE_REMOTE_FOREGROUND = registerColor('extensionBadge.remoteForeground', { dark: ACTIVITY_BAR_BADGE_FOREGROUND, light: ACTIVITY_BAR_BADGE_FOREGROUND, hc: ACTIVITY_BAR_BADGE_FOREGROUND -}, nls.localize('extensionBadge.remoteForeground', "Foreground color for the remote badge in the extensions view")); +}, nls.localize('extensionBadge.remoteForeground', "Foreground color for the remote badge in the extensions view.")); // < --- Side Bar --- > @@ -449,13 +449,13 @@ export const QUICK_INPUT_BACKGROUND = registerColor('quickInput.background', { dark: SIDE_BAR_BACKGROUND, light: SIDE_BAR_BACKGROUND, hc: SIDE_BAR_BACKGROUND -}, nls.localize('quickInputBackground', "Quick Input background color. The Quick Input widget is the container for views like the color theme picker")); +}, nls.localize('quickInputBackground', "Quick Input background color. The Quick Input widget is the container for views like the color theme picker.")); export const QUICK_INPUT_FOREGROUND = registerColor('quickInput.foreground', { dark: SIDE_BAR_FOREGROUND, light: SIDE_BAR_FOREGROUND, hc: SIDE_BAR_FOREGROUND -}, nls.localize('quickInputForeground', "Quick Input foreground color. The Quick Input widget is the container for views like the color theme picker")); +}, nls.localize('quickInputForeground', "Quick Input foreground color. The Quick Input widget is the container for views like the color theme picker.")); // < --- Title Bar --- > diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index c575d45278..c4b1fdc87f 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -10,7 +10,7 @@ import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/con import { ITreeViewDataProvider } from 'vs/workbench/common/views'; import { localize } from 'vs/nls'; import { IViewlet } from 'vs/workbench/common/viewlet'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { values, keys } from 'vs/base/common/map'; @@ -295,7 +295,7 @@ export interface IViewsViewlet extends IViewlet { export const IViewsService = createDecorator('viewsService'); export interface IViewsService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; openView(id: string, focus?: boolean): Promise; @@ -314,6 +314,8 @@ export interface ITreeView extends IDisposable { message?: string; + title: string; + readonly visible: boolean; readonly onDidExpandItem: Event; @@ -326,6 +328,8 @@ export interface ITreeView extends IDisposable { readonly onDidChangeActions: Event; + readonly onDidChangeTitle: Event; + refresh(treeItems?: ITreeItem[]): Promise; setVisibility(visible: boolean): void; diff --git a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts index 7b75200087..8ca19c5a9c 100644 --- a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts +++ b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { CallHierarchyProviderRegistry, CallHierarchyDirection } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; +import { CallHierarchyProviderRegistry, CallHierarchyDirection } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { CallHierarchyTreePeekWidget } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek'; @@ -13,16 +13,18 @@ import { registerEditorContribution, registerEditorAction, EditorAction, registe import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { IContextKeyService, RawContextKey, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { PeekContext } from 'vs/editor/contrib/referenceSearch/peekViewWidget'; +import { CallHierarchyRoot } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchyTree'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; const _ctxHasCompletionItemProvider = new RawContextKey('editorHasCallHierarchyProvider', false); const _ctxCallHierarchyVisible = new RawContextKey('callHierarchyVisible', false); -class CallHierarchyController extends Disposable implements IEditorContribution { +class CallHierarchyController implements IEditorContribution { static Id = 'callHierarchy'; @@ -30,31 +32,31 @@ class CallHierarchyController extends Disposable implements IEditorContribution return editor.getContribution(CallHierarchyController.Id); } + private static _StorageDirection = 'callHierarchy/defaultDirection'; + private readonly _ctxHasProvider: IContextKey; private readonly _ctxIsVisible: IContextKey; - - private _sessionDispose: IDisposable[] = []; + private readonly _dispoables = new DisposableStore(); + private readonly _sessionDisposables = new DisposableStore(); constructor( private readonly _editor: ICodeEditor, @IContextKeyService private readonly _contextKeyService: IContextKeyService, + @IStorageService private readonly _storageService: IStorageService, @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { - super(); - this._ctxIsVisible = _ctxCallHierarchyVisible.bindTo(this._contextKeyService); this._ctxHasProvider = _ctxHasCompletionItemProvider.bindTo(this._contextKeyService); - this._register(Event.any(_editor.onDidChangeModel, _editor.onDidChangeModelLanguage, CallHierarchyProviderRegistry.onDidChange)(() => { + this._dispoables.add(Event.any(_editor.onDidChangeModel, _editor.onDidChangeModelLanguage, CallHierarchyProviderRegistry.onDidChange)(() => { this._ctxHasProvider.set(_editor.hasModel() && CallHierarchyProviderRegistry.has(_editor.getModel())); })); - - this._register({ dispose: () => dispose(this._sessionDispose) }); + this._dispoables.add(this._sessionDisposables); } dispose(): void { this._ctxHasProvider.reset(); this._ctxIsVisible.reset(); - super.dispose(); + this._dispoables.dispose(); } getId(): string { @@ -62,7 +64,7 @@ class CallHierarchyController extends Disposable implements IEditorContribution } async startCallHierarchy(): Promise { - this._sessionDispose = dispose(this._sessionDispose); + this._sessionDisposables.clear(); if (!this._editor.hasModel()) { return; @@ -75,13 +77,15 @@ class CallHierarchyController extends Disposable implements IEditorContribution return; } - Event.any(this._editor.onDidChangeModel, this._editor.onDidChangeModelLanguage)(this.endCallHierarchy, this, this._sessionDispose); + const direction = this._storageService.getNumber(CallHierarchyController._StorageDirection, StorageScope.GLOBAL, CallHierarchyDirection.CallsFrom); + + Event.any(this._editor.onDidChangeModel, this._editor.onDidChangeModelLanguage)(this.endCallHierarchy, this, this._sessionDisposables); const widget = this._instantiationService.createInstance( CallHierarchyTreePeekWidget, this._editor, position, provider, - CallHierarchyDirection.CallsTo + direction ); widget.showLoading(); @@ -89,24 +93,23 @@ class CallHierarchyController extends Disposable implements IEditorContribution const cancel = new CancellationTokenSource(); - this._sessionDispose.push(widget.onDidClose(() => this.endCallHierarchy())); - this._sessionDispose.push({ dispose() { cancel.cancel(); } }); - this._sessionDispose.push(widget); + this._sessionDisposables.add(widget.onDidClose(() => { + this.endCallHierarchy(); + this._storageService.store(CallHierarchyController._StorageDirection, widget.direction, StorageScope.GLOBAL); + })); + this._sessionDisposables.add({ dispose() { cancel.cancel(); } }); + this._sessionDisposables.add(widget); - Promise.resolve(provider.provideCallHierarchyItem(model, position, cancel.token)).then(item => { - if (cancel.token.isCancellationRequested) { - return; - } - if (!item) { - widget.showMessage(localize('no.item', "No results")); - return; - } - widget.showItem(item); - }); + const root = CallHierarchyRoot.fromEditor(this._editor); + if (root) { + widget.showItem(root); + } else { + widget.showMessage(localize('no.item', "No results")); + } } endCallHierarchy(): void { - this._sessionDispose = dispose(this._sessionDispose); + this._sessionDisposables.clear(); this._ctxIsVisible.set(false); this._editor.focus(); } diff --git a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.ts new file mode 100644 index 0000000000..08e26868fe --- /dev/null +++ b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.ts @@ -0,0 +1,84 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IRange } from 'vs/editor/common/core/range'; +import { SymbolKind, ProviderResult } from 'vs/editor/common/modes'; +import { ITextModel } from 'vs/editor/common/model'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureRegistry'; +import { URI } from 'vs/base/common/uri'; +import { IPosition } from 'vs/editor/common/core/position'; +import { registerDefaultLanguageCommand } from 'vs/editor/browser/editorExtensions'; +import { isNonEmptyArray } from 'vs/base/common/arrays'; +import { onUnexpectedExternalError } from 'vs/base/common/errors'; + +export const enum CallHierarchyDirection { + CallsTo = 1, + CallsFrom = 2 +} + +export interface CallHierarchyItem { + kind: SymbolKind; + name: string; + detail?: string; + uri: URI; + range: IRange; + selectionRange: IRange; +} + +export interface IncomingCall { + source: CallHierarchyItem; + sourceRanges: IRange[]; +} + +export interface OutgoingCall { + sourceRanges: IRange[]; + target: CallHierarchyItem; +} + +export interface CallHierarchyProvider { + + provideIncomingCalls(document: ITextModel, postion: IPosition, token: CancellationToken): ProviderResult; + + provideOutgoingCalls(document: ITextModel, postion: IPosition, token: CancellationToken): ProviderResult; +} + +export const CallHierarchyProviderRegistry = new LanguageFeatureRegistry(); + + +export async function provideIncomingCalls(model: ITextModel, position: IPosition, token: CancellationToken): Promise { + const [provider] = CallHierarchyProviderRegistry.ordered(model); + if (!provider) { + return []; + } + try { + const result = await provider.provideIncomingCalls(model, position, token); + if (isNonEmptyArray(result)) { + return result; + } + } catch (e) { + onUnexpectedExternalError(e); + } + return []; +} + +export async function provideOutgoingCalls(model: ITextModel, position: IPosition, token: CancellationToken): Promise { + const [provider] = CallHierarchyProviderRegistry.ordered(model); + if (!provider) { + return []; + } + try { + const result = await provider.provideOutgoingCalls(model, position, token); + if (isNonEmptyArray(result)) { + return result; + } + } catch (e) { + onUnexpectedExternalError(e); + } + return []; +} + +registerDefaultLanguageCommand('_executeCallHierarchyIncomingCalls', async (model, position) => provideIncomingCalls(model, position, CancellationToken.None)); +registerDefaultLanguageCommand('_executeCallHierarchyOutgoingCalls', async (model, position) => provideOutgoingCalls(model, position, CancellationToken.None)); diff --git a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts index 5d068f18f3..7ed5c18eef 100644 --- a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts +++ b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts @@ -7,7 +7,7 @@ import 'vs/css!./media/callHierarchy'; import { PeekViewWidget, IPeekViewService } from 'vs/editor/contrib/referenceSearch/peekViewWidget'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { CallHierarchyProvider, CallHierarchyDirection, CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; +import { CallHierarchyProvider, CallHierarchyDirection } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy'; import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService'; import { FuzzyScore } from 'vs/base/common/filters'; import * as callHTree from 'vs/workbench/contrib/callHierarchy/browser/callHierarchyTree'; @@ -22,18 +22,17 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { TrackedRangeStickiness, IModelDeltaDecoration, IModelDecorationOptions, OverviewRulerLane } from 'vs/editor/common/model'; import { registerThemingParticipant, themeColorFromId, IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import * as referencesWidget from 'vs/editor/contrib/referenceSearch/referencesWidget'; -import { isNonEmptyArray } from 'vs/base/common/arrays'; import { IPosition } from 'vs/editor/common/core/position'; import { Action } from 'vs/base/common/actions'; import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; -import { ILabelService } from 'vs/platform/label/common/label'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { Color } from 'vs/base/common/color'; import { TreeMouseEventTarget } from 'vs/base/browser/ui/tree/tree'; +import { URI } from 'vs/base/common/uri'; const enum State { Loading = 'loading', @@ -95,7 +94,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { private _parent!: HTMLElement; private _message!: HTMLElement; private _splitView!: SplitView; - private _tree!: WorkbenchAsyncDataTree; + private _tree!: WorkbenchAsyncDataTree; private _treeViewStates = new Map(); private _editor!: EmbeddedCodeEditorWidget; private _dim!: Dimension; @@ -110,7 +109,6 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { @IPeekViewService private readonly _peekViewService: IPeekViewService, @IEditorService private readonly _editorService: IEditorService, @ITextModelService private readonly _textModelService: ITextModelService, - @ILabelService private readonly _labelService: ILabelService, @IStorageService private readonly _storageService: IStorageService, @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { @@ -129,6 +127,10 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { super.dispose(); } + get direction(): CallHierarchyDirection { + return this._direction; + } + private _applyTheme(theme: ITheme) { const borderColor = theme.getColor(referencesWidget.peekViewBorder) || Color.transparent; this.style({ @@ -197,16 +199,17 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { addClass(treeContainer, 'tree'); container.appendChild(treeContainer); const options: IAsyncDataTreeOptions = { - identityProvider: new callHTree.IdentityProvider(), + identityProvider: new callHTree.IdentityProvider(() => this._direction), ariaLabel: localize('tree.aria', "Call Hierarchy"), expandOnlyOnTwistieClick: true, }; this._tree = this._instantiationService.createInstance( WorkbenchAsyncDataTree, + 'CallHierarchyPeek', treeContainer, new callHTree.VirtualDelegate(), [this._instantiationService.createInstance(callHTree.CallRenderer)], - new callHTree.SingleDirectionDataSource(this._provider, () => this._direction), + this._instantiationService.createInstance(callHTree.DataSource, this._provider, () => this._direction), options ); @@ -217,7 +220,9 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { minimumSize: 200, maximumSize: Number.MAX_VALUE, layout: (width) => { - this._editor.layout({ height: this._dim.height, width }); + if (this._dim.height) { + this._editor.layout({ height: this._dim.height, width }); + } } }, Sizing.Distribute); @@ -227,7 +232,9 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { minimumSize: 100, maximumSize: Number.MAX_VALUE, layout: (width) => { - this._tree.layout(this._dim.height, width); + if (this._dim.height) { + this._tree.layout(this._dim.height, width); + } } }, Sizing.Distribute); @@ -238,56 +245,79 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { })); // session state - let localDispose: IDisposable[] = []; - this._disposables.add({ dispose() { dispose(localDispose); } }); + const localDispose = new DisposableStore(); + this._disposables.add(localDispose); // update editor - this._disposables.add(this._tree.onDidChangeFocus(e => { + this._disposables.add(this._tree.onDidChangeFocus(async e => { const [element] = e.elements; - if (element && isNonEmptyArray(element.locations)) { - - localDispose = dispose(localDispose); - - const options: IModelDecorationOptions = { - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - className: 'call-decoration', - overviewRuler: { - color: themeColorFromId(referencesWidget.peekViewEditorMatchHighlight), - position: OverviewRulerLane.Center - }, - }; - let decorations: IModelDeltaDecoration[] = []; - let fullRange: IRange | undefined; - for (const { range } of element.locations) { - decorations.push({ range, options }); - fullRange = !fullRange ? range : Range.plusRange(range, fullRange); - } - - this._textModelService.createModelReference(element.item.uri).then(value => { - this._editor.setModel(value.object.textEditorModel); - this._editor.revealRangeInCenter(fullRange!, ScrollType.Smooth); - this._editor.revealLine(element.item.range.startLineNumber, ScrollType.Smooth); - const ids = this._editor.deltaDecorations([], decorations); - localDispose.push({ dispose: () => this._editor.deltaDecorations(ids, []) }); - localDispose.push(value); - }); - - let node: callHTree.Call | CallHierarchyItem = element; - let names = [element.item.name]; - while (true) { - let parent = this._tree.getParentElement(node); - if (!(parent instanceof callHTree.Call)) { - break; - } - if (this._direction === CallHierarchyDirection.CallsTo) { - names.push(parent.item.name); - } else { - names.unshift(parent.item.name); - } - node = parent; - } - this.setMetaTitle(localize('meta', " – {0}", names.join(' → '))); + if (!element) { + return; } + + localDispose.clear(); + + // update: editor and editor highlights + const options: IModelDecorationOptions = { + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + className: 'call-decoration', + overviewRuler: { + color: themeColorFromId(referencesWidget.peekViewEditorMatchHighlight), + position: OverviewRulerLane.Center + }, + }; + + let previewUri: URI; + if (this._direction === CallHierarchyDirection.CallsFrom) { + // outgoing calls: show caller and highlight focused calls + previewUri = element.parent ? element.parent.item.uri : this._tree.getInput()!.model.uri; + } else { + // incoming calls: show caller and highlight focused calls + previewUri = element.item.uri; + } + + const value = await this._textModelService.createModelReference(previewUri); + this._editor.setModel(value.object.textEditorModel); + + // set decorations for caller ranges (if in the same file) + let decorations: IModelDeltaDecoration[] = []; + let fullRange: IRange | undefined; + for (const loc of element.locations) { + if (loc.uri.toString() === previewUri.toString()) { + decorations.push({ range: loc.range, options }); + fullRange = !fullRange ? loc.range : Range.plusRange(loc.range, fullRange); + } + } + if (fullRange) { + this._editor.revealRangeInCenter(fullRange, ScrollType.Immediate); + const ids = this._editor.deltaDecorations([], decorations); + localDispose.add(toDisposable(() => this._editor.deltaDecorations(ids, []))); + } + localDispose.add(value); + + // update: title and subtitle + let node: callHTree.Call | undefined = element; + let names = [element.item.name]; + while (node) { + let parent = this._tree.getParentElement(node); + let name: string; + if (parent instanceof callHTree.Call) { + name = parent.item.name; + node = parent; + } else { + name = this._tree.getInput()!.word; + node = undefined; + } + if (this._direction === CallHierarchyDirection.CallsTo) { + names.push(name); + } else { + names.unshift(name); + } + } + const title = this._direction === CallHierarchyDirection.CallsFrom + ? localize('callFrom', "Calls from '{0}'", this._tree.getInput()!.word) + : localize('callsTo', "Callers of '{0}'", this._tree.getInput()!.word); + this.setTitle(title, names.join(' → ')); })); this._disposables.add(this._editor.onMouseDown(e => { @@ -312,11 +342,11 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { return; } - if (e.element && isNonEmptyArray(e.element.locations)) { + if (e.element) { this.dispose(); this._editorService.openEditor({ resource: e.element.item.uri, - options: { selection: e.element.locations[0].range } + options: { selection: e.element.item.selectionRange } }); } })); @@ -324,11 +354,11 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { this._disposables.add(this._tree.onDidChangeSelection(e => { const [element] = e.elements; // don't close on click - if (element && isNonEmptyArray(element.locations) && e.browserEvent instanceof KeyboardEvent) { + if (element && e.browserEvent instanceof KeyboardEvent) { this.dispose(); this._editorService.openEditor({ resource: element.item.uri, - options: { selection: element.locations[0].range } + options: { selection: element.item.selectionRange } }); } })); @@ -349,31 +379,24 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { this._message.focus(); } - async showItem(item: CallHierarchyItem): Promise { + async showItem(item: callHTree.CallHierarchyRoot): Promise { this._show(); const viewState = this._treeViewStates.get(this._direction); await this._tree.setInput(item, viewState); - const [root] = this._tree.getNode(item).children; - await this._tree.expand(root.element as callHTree.Call); - const firstChild = this._tree.getFirstElementChild(root.element); - if (!(firstChild instanceof callHTree.Call)) { + if (this._tree.getNode(item).children.length === 0) { // this.showMessage(this._direction === CallHierarchyDirection.CallsFrom - ? localize('empt.callsFrom', "No calls from '{0}'", item.name) - : localize('empt.callsTo', "No calls to '{0}'", item.name)); + ? localize('empt.callsFrom', "No calls from '{0}'", item.word) + : localize('empt.callsTo', "No callers of '{0}'", item.word)); } else { this._parent.dataset['state'] = State.Data; this._tree.domFocus(); if (!viewState) { - this._tree.setFocus([firstChild]); + this._tree.focusFirst(); } - this.setTitle( - item.name, - item.detail || this._labelService.getUriLabel(item.uri, { relative: true }), - ); } if (!this._changeDirectionAction) { @@ -381,7 +404,8 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { if (this._direction !== newDirection) { this._treeViewStates.set(this._direction, this._tree.getViewState()); this._direction = newDirection; - this.showItem(item); + this._tree.setFocus([]); + this.showItem(this._tree.getInput()!); } }; this._changeDirectionAction = new ChangeHierarchyDirectionAction(this._direction, changeDirection); @@ -404,11 +428,13 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { } protected _doLayoutBody(height: number, width: number): void { - super._doLayoutBody(height, width); - this._dim = { height, width }; - this._layoutInfo.height = this._viewZone ? this._viewZone.heightInLines : this._layoutInfo.height; - this._splitView.layout(width); - this._splitView.resizeView(0, width * this._layoutInfo.ratio); + if (this._dim.height !== height || this._dim.width === width) { + super._doLayoutBody(height, width); + this._dim = { height, width }; + this._layoutInfo.height = this._viewZone ? this._viewZone.heightInLines : this._layoutInfo.height; + this._splitView.layout(width); + this._splitView.resizeView(0, width * this._layoutInfo.ratio); + } } } diff --git a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts index 97cdd1eb4b..da33988229 100644 --- a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts +++ b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts @@ -4,14 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import { IAsyncDataSource, ITreeRenderer, ITreeNode } from 'vs/base/browser/ui/tree/tree'; -import { CallHierarchyItem, CallHierarchyDirection, CallHierarchyProvider } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; +import { CallHierarchyItem, CallHierarchyProvider, CallHierarchyDirection, provideOutgoingCalls, provideIncomingCalls } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IIdentityProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { FuzzyScore, createMatches } from 'vs/base/common/filters'; import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { symbolKindToCssClass, Location } from 'vs/editor/common/modes'; -import { Range } from 'vs/editor/common/core/range'; import { hash } from 'vs/base/common/hash'; +import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { Range } from 'vs/editor/common/core/range'; +import { ITextModel } from 'vs/editor/common/model'; +import { IPosition } from 'vs/editor/common/core/position'; +import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; export class Call { constructor( @@ -21,39 +25,92 @@ export class Call { ) { } } -export class SingleDirectionDataSource implements IAsyncDataSource { +export class CallHierarchyRoot { + + static fromEditor(editor: IActiveCodeEditor): CallHierarchyRoot | undefined { + const model = editor.getModel(); + const position = editor.getPosition(); + const wordInfo = model.getWordAtPosition(position); + return wordInfo + ? new CallHierarchyRoot(model, position, wordInfo.word) + : undefined; + } + + constructor( + readonly model: ITextModel, + readonly position: IPosition, + readonly word: string + ) { } +} + +export class DataSource implements IAsyncDataSource { constructor( public provider: CallHierarchyProvider, - public getDirection: () => CallHierarchyDirection + public getDirection: () => CallHierarchyDirection, + @ITextModelService private readonly _modelService: ITextModelService, ) { } hasChildren(): boolean { return true; } - async getChildren(element: CallHierarchyItem | Call): Promise { - if (element instanceof Call) { - try { - const direction = this.getDirection(); - const calls = await this.provider.resolveCallHierarchyItem(element.item, direction, CancellationToken.None); - if (!calls) { - return []; - } - return calls.map(([item, locations]) => new Call(item, locations, element)); - } catch { - return []; + async getChildren(element: CallHierarchyRoot | Call): Promise { + + const results: Call[] = []; + + if (element instanceof CallHierarchyRoot) { + if (this.getDirection() === CallHierarchyDirection.CallsFrom) { + await this._getOutgoingCalls(element.model, element.position, results); + } else { + await this._getIncomingCalls(element.model, element.position, results); } } else { - // 'root' - return [new Call(element, [{ uri: element.uri, range: Range.lift(element.range).collapseToStart() }], undefined)]; + const reference = await this._modelService.createModelReference(element.item.uri); + const position = Range.lift(element.item.selectionRange).getStartPosition(); + if (this.getDirection() === CallHierarchyDirection.CallsFrom) { + await this._getOutgoingCalls(reference.object.textEditorModel, position, results, element); + } else { + await this._getIncomingCalls(reference.object.textEditorModel, position, results, element); + } + reference.dispose(); + } + + return results; + } + + private async _getOutgoingCalls(model: ITextModel, position: IPosition, bucket: Call[], parent?: Call): Promise { + const outgoingCalls = await provideOutgoingCalls(model, position, CancellationToken.None); + for (const call of outgoingCalls) { + bucket.push(new Call( + call.target, + call.sourceRanges.map(range => ({ range, uri: model.uri })), + parent + )); } } + + private async _getIncomingCalls(model: ITextModel, position: IPosition, bucket: Call[], parent?: Call): Promise { + const incomingCalls = await provideIncomingCalls(model, position, CancellationToken.None); + for (const call of incomingCalls) { + bucket.push(new Call( + call.source, + call.sourceRanges.map(range => ({ range, uri: call.source.uri })), + parent + )); + } + } + } export class IdentityProvider implements IIdentityProvider { + + constructor( + public getDirection: () => CallHierarchyDirection + ) { } + getId(element: Call): { toString(): string; } { - return hash(element.item.uri.toString(), hash(JSON.stringify(element.item.range))).toString() + (element.parent ? this.getId(element.parent) : ''); + return this.getDirection() + hash(element.item.uri.toString(), hash(JSON.stringify(element.item.range))).toString() + (element.parent ? this.getId(element.parent) : ''); } } diff --git a/src/vs/workbench/contrib/callHierarchy/browser/media/callHierarchy.css b/src/vs/workbench/contrib/callHierarchy/browser/media/callHierarchy.css index a619224f62..2a1b344742 100644 --- a/src/vs/workbench/contrib/callHierarchy/browser/media/callHierarchy.css +++ b/src/vs/workbench/contrib/callHierarchy/browser/media/callHierarchy.css @@ -10,6 +10,7 @@ .monaco-workbench .call-hierarchy[data-state="data"] .results { display: inherit; + height: 100%; } .monaco-workbench .call-hierarchy[data-state="message"] .message { @@ -33,11 +34,7 @@ background-position: left center; } -.monaco-workbench .call-hierarchy .monaco-split-view2.horizontal > .split-view-container > .split-view-view { - /* this is a little bizare.. */ - height: unset; -} - +.monaco-workbench .call-hierarchy .editor, .monaco-workbench .call-hierarchy .tree { height: 100%; } diff --git a/src/vs/workbench/contrib/callHierarchy/common/callHierarchy.ts b/src/vs/workbench/contrib/callHierarchy/common/callHierarchy.ts deleted file mode 100644 index 42c548ac9d..0000000000 --- a/src/vs/workbench/contrib/callHierarchy/common/callHierarchy.ts +++ /dev/null @@ -1,45 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IPosition } from 'vs/editor/common/core/position'; -import { IRange } from 'vs/editor/common/core/range'; -import { SymbolKind, ProviderResult, Location } from 'vs/editor/common/modes'; -import { ITextModel } from 'vs/editor/common/model'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureRegistry'; -import { URI } from 'vs/base/common/uri'; - -export const enum CallHierarchyDirection { - CallsFrom = 1, - CallsTo = 2 -} - -export interface CallHierarchyItem { - _id: number; - kind: SymbolKind; - name: string; - detail?: string; - uri: URI; - range: IRange; - selectionRange: IRange; -} - -export interface CallHierarchyProvider { - - provideCallHierarchyItem( - document: ITextModel, - position: IPosition, - token: CancellationToken - ): ProviderResult; - - resolveCallHierarchyItem( - item: CallHierarchyItem, - direction: CallHierarchyDirection, - token: CancellationToken - ): ProviderResult<[CallHierarchyItem, Location[]][]>; -} - -export const CallHierarchyProviderRegistry = new LanguageFeatureRegistry(); - diff --git a/src/vs/workbench/contrib/cli/node/cli.contribution.ts b/src/vs/workbench/contrib/cli/node/cli.contribution.ts index a71f7369da..9fa727e74c 100644 --- a/src/vs/workbench/contrib/cli/node/cli.contribution.ts +++ b/src/vs/workbench/contrib/cli/node/cli.contribution.ts @@ -101,8 +101,8 @@ class InstallAction extends Action { return new Promise((resolve, reject) => { const buttons = [nls.localize('ok', "OK"), nls.localize('cancel2', "Cancel")]; - this.dialogService.show(Severity.Info, nls.localize('warnEscalation', "Code will now prompt with 'osascript' for Administrator privileges to install the shell command."), buttons, { cancelId: 1 }).then(choice => { - switch (choice) { + this.dialogService.show(Severity.Info, nls.localize('warnEscalation', "Code will now prompt with 'osascript' for Administrator privileges to install the shell command."), buttons, { cancelId: 1 }).then(result => { + switch (result.choice) { case 0 /* OK */: const command = 'osascript -e "do shell script \\"mkdir -p /usr/local/bin && ln -sf \'' + getSource() + '\' \'' + this.target + '\'\\" with administrator privileges"'; @@ -165,23 +165,22 @@ class UninstallAction extends Action { } private deleteSymlinkAsAdmin(): Promise { - return new Promise((resolve, reject) => { + return new Promise(async (resolve, reject) => { const buttons = [nls.localize('ok', "OK"), nls.localize('cancel2', "Cancel")]; - this.dialogService.show(Severity.Info, nls.localize('warnEscalationUninstall', "Code will now prompt with 'osascript' for Administrator privileges to uninstall the shell command."), buttons, { cancelId: 1 }).then(choice => { - switch (choice) { - case 0 /* OK */: - const command = 'osascript -e "do shell script \\"rm \'' + this.target + '\'\\" with administrator privileges"'; + const { choice } = await this.dialogService.show(Severity.Info, nls.localize('warnEscalationUninstall', "Code will now prompt with 'osascript' for Administrator privileges to uninstall the shell command."), buttons, { cancelId: 1 }); + switch (choice) { + case 0 /* OK */: + const command = 'osascript -e "do shell script \\"rm \'' + this.target + '\'\\" with administrator privileges"'; - promisify(cp.exec)(command, {}) - .then(undefined, _ => Promise.reject(new Error(nls.localize('cantUninstall', "Unable to uninstall the shell command '{0}'.", this.target)))) - .then(resolve, reject); - break; - case 1 /* Cancel */: - reject(new Error(nls.localize('aborted', "Aborted"))); - break; - } - }); + promisify(cp.exec)(command, {}) + .then(undefined, _ => Promise.reject(new Error(nls.localize('cantUninstall', "Unable to uninstall the shell command '{0}'.", this.target)))) + .then(resolve, reject); + break; + case 1 /* Cancel */: + reject(new Error(nls.localize('aborted', "Aborted"))); + break; + } }); } } diff --git a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts index 90b06f46d5..08718cbffe 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts @@ -17,7 +17,7 @@ import * as strings from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { EditorAction, EditorCommand, registerEditorAction, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ToggleTabFocusModeAction } from 'vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode'; @@ -185,13 +185,13 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { } private _buildContent() { - let opts = this._editor.getConfiguration(); + const options = this._editor.getOptions(); let text = nls.localize('introMsg', "Thank you for trying out VS Code's accessibility options."); text += '\n\n' + nls.localize('status', "Status:"); - const configuredValue = this._configurationService.getValue('editor').accessibilitySupport; - const actualValue = opts.accessibilitySupport; + const configuredValue = this._configurationService.getValue('editor').accessibilitySupport; + const actualValue = options.get(EditorOption.accessibilitySupport); const emergencyTurnOnMessage = ( platform.isMacintosh @@ -229,7 +229,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { const NLS_TAB_FOCUS_MODE_OFF = nls.localize('tabFocusModeOffMsg', "Pressing Tab in the current editor will insert the tab character. Toggle this behavior by pressing {0}."); const NLS_TAB_FOCUS_MODE_OFF_NO_KB = nls.localize('tabFocusModeOffMsgNoKb', "Pressing Tab in the current editor will insert the tab character. The command {0} is currently not triggerable by a keybinding."); - if (opts.tabFocusMode) { + if (options.get(EditorOption.tabFocusMode)) { text += '\n\n - ' + this._descriptionForCommand(ToggleTabFocusModeAction.ID, NLS_TAB_FOCUS_MODE_ON, NLS_TAB_FOCUS_MODE_ON_NO_KB); } else { text += '\n\n - ' + this._descriptionForCommand(ToggleTabFocusModeAction.ID, NLS_TAB_FOCUS_MODE_OFF, NLS_TAB_FOCUS_MODE_OFF_NO_KB); diff --git a/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts index 2a63c430c5..c614e74e09 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts @@ -59,7 +59,7 @@ export abstract class SimpleFindWidget extends Widget { return null; } catch (e) { this.foundMatch = false; - this._updateButtons(); + this.updateButtons(this.foundMatch); return { content: e.message }; } } @@ -70,7 +70,7 @@ export abstract class SimpleFindWidget extends Widget { this.oninput(this._findInput.domNode, (e) => { this.foundMatch = this.onInputChanged(); - this._updateButtons(); + this.updateButtons(this.foundMatch); this._delayedUpdateHistory(); }); @@ -209,7 +209,7 @@ export abstract class SimpleFindWidget extends Widget { } this._isVisible = true; - this._updateButtons(); + this.updateButtons(this.foundMatch); setTimeout(() => { dom.addClass(this._innerDomNode, 'visible'); @@ -240,7 +240,7 @@ export abstract class SimpleFindWidget extends Widget { // Need to delay toggling visibility until after Transition, then visibility hidden - removes from tabIndex list setTimeout(() => { this._isVisible = false; - this._updateButtons(); + this.updateButtons(this.foundMatch); dom.removeClass(this._innerDomNode, 'visible'); }, 200); } @@ -266,10 +266,10 @@ export abstract class SimpleFindWidget extends Widget { return this._findInput.getCaseSensitive(); } - private _updateButtons() { - let hasInput = this.inputValue.length > 0; - this.prevBtn.setEnabled(this._isVisible && hasInput && this.foundMatch); - this.nextBtn.setEnabled(this._isVisible && hasInput && this.foundMatch); + protected updateButtons(foundMatch: boolean) { + const hasInput = this.inputValue.length > 0; + this.prevBtn.setEnabled(this._isVisible && hasInput && foundMatch); + this.nextBtn.setEnabled(this._isVisible && hasInput && foundMatch); } } diff --git a/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts b/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts index c14da81a7f..323b28cc2b 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts @@ -17,6 +17,7 @@ import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/c import { Registry } from 'vs/platform/registry/common/platform'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService'; +import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; interface IRegExp { pattern: string; @@ -101,7 +102,7 @@ export class LanguageConfigurationFileHandler { const errors: ParseError[] = []; const configuration = parse(contents.value.toString(), errors); if (errors.length) { - console.error(nls.localize('parseErrors', "Errors parsing {0}: {1}", configFileLocation.toString(), errors.join('\n'))); + console.error(nls.localize('parseErrors', "Errors parsing {0}: {1}", configFileLocation.toString(), errors.map(e => (`[${e.offset}, ${e.length}] ${getParseErrorMessage(e.error)}`)).join('\n'))); } this._handleConfig(languageIdentifier, configuration); }, (err) => { @@ -358,6 +359,7 @@ export class LanguageConfigurationFileHandler { const schemaId = 'vscode://schemas/language-configuration'; const schema: IJSONSchema = { allowComments: true, + allowsTrailingCommas: true, default: { comments: { blockComment: ['/*', '*/'], diff --git a/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts b/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts index 0669d98adb..7c46216773 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts @@ -9,7 +9,7 @@ import * as process from 'vs/base/common/process'; import * as platform from 'vs/base/common/platform'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { Range } from 'vs/editor/common/core/range'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; @@ -24,11 +24,11 @@ export class SelectionClipboard extends Disposable implements IEditorContributio super(); if (platform.isLinux) { - let isEnabled = editor.getConfiguration().contribInfo.selectionClipboard; + let isEnabled = editor.getOption(EditorOption.selectionClipboard); - this._register(editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - if (e.contribInfo) { - isEnabled = editor.getConfiguration().contribInfo.selectionClipboard; + this._register(editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.selectionClipboard)) { + isEnabled = editor.getOption(EditorOption.selectionClipboard); } })); diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts index 8cb6e813fb..ac0779e5c3 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts @@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { EDITOR_DEFAULTS, InternalEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { EditorOption, EditorOptions } from 'vs/editor/common/config/editorOptions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; @@ -19,6 +19,7 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { DefaultSettingsEditorContribution } from 'vs/workbench/contrib/preferences/browser/preferencesEditor'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; const transientWordWrapState = 'transientWordWrapState'; const isWordWrapMinifiedKey = 'isWordWrapMinified'; @@ -68,7 +69,7 @@ function readWordWrapState(model: ITextModel, configurationService: ITextResourc const _transientState = readTransientState(model, codeEditorService); return { configuredWordWrap: _configuredWordWrap, - configuredWordWrapMinified: (typeof _configuredWordWrapMinified === 'boolean' ? _configuredWordWrapMinified : EDITOR_DEFAULTS.wordWrapMinified), + configuredWordWrapMinified: (typeof _configuredWordWrapMinified === 'boolean' ? _configuredWordWrapMinified : EditorOptions.wordWrapMinified.defaultValue), transientState: _transientState }; } @@ -83,10 +84,9 @@ function toggleWordWrap(editor: ICodeEditor, state: IWordWrapState): IWordWrapSt }; } - const config = editor.getConfiguration(); let transientState: IWordWrapTransientState; - const actualWrappingInfo = config.wrappingInfo; + const actualWrappingInfo = editor.getOption(EditorOption.wrappingInfo); if (actualWrappingInfo.isWordWrapMinified) { // => wrapping due to minified file transientState = { @@ -139,8 +139,7 @@ class ToggleWordWrapAction extends EditorAction { if (!editor.hasModel()) { return; } - const editorConfiguration = editor.getConfiguration(); - if (editorConfiguration.wrappingInfo.inDiffEditor) { + if (editor.getOption(EditorOption.inDiffEditor)) { // Cannot change wrapping settings inside the diff editor const notificationService = accessor.get(INotificationService); notificationService.info(nls.localize('wordWrap.notInDiffEditor', "Cannot toggle word wrap in a diff editor.")); @@ -177,20 +176,22 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution ) { super(); - const configuration = this.editor.getConfiguration(); - const isWordWrapMinified = this.contextKeyService.createKey(isWordWrapMinifiedKey, this._isWordWrapMinified(configuration)); - const isDominatedByLongLines = this.contextKeyService.createKey(isDominatedByLongLinesKey, this._isDominatedByLongLines(configuration)); - const inDiffEditor = this.contextKeyService.createKey(inDiffEditorKey, this._inDiffEditor(configuration)); + const options = this.editor.getOptions(); + const wrappingInfo = options.get(EditorOption.wrappingInfo); + const isWordWrapMinified = this.contextKeyService.createKey(isWordWrapMinifiedKey, wrappingInfo.isWordWrapMinified); + const isDominatedByLongLines = this.contextKeyService.createKey(isDominatedByLongLinesKey, wrappingInfo.isDominatedByLongLines); + const inDiffEditor = this.contextKeyService.createKey(inDiffEditorKey, options.get(EditorOption.inDiffEditor)); let currentlyApplyingEditorConfig = false; this._register(editor.onDidChangeConfiguration((e) => { - if (!e.wrappingInfo) { + if (!e.hasChanged(EditorOption.wrappingInfo) && !e.hasChanged(EditorOption.inDiffEditor)) { return; } - const configuration = this.editor.getConfiguration(); - isWordWrapMinified.set(this._isWordWrapMinified(configuration)); - isDominatedByLongLines.set(this._isDominatedByLongLines(configuration)); - inDiffEditor.set(this._inDiffEditor(configuration)); + const options = this.editor.getOptions(); + const wrappingInfo = options.get(EditorOption.wrappingInfo); + isWordWrapMinified.set(wrappingInfo.isWordWrapMinified); + isDominatedByLongLines.set(wrappingInfo.isDominatedByLongLines); + inDiffEditor.set(options.get(EditorOption.inDiffEditor)); if (!currentlyApplyingEditorConfig) { // I am not the cause of the word wrap getting changed ensureWordWrapSettings(); @@ -216,8 +217,7 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution return; } - const configuration = this.editor.getConfiguration(); - if (this._inDiffEditor(configuration)) { + if (this.editor.getOption(EditorOption.inDiffEditor)) { return; } @@ -255,18 +255,6 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution }); } - private _isWordWrapMinified(config: InternalEditorOptions): boolean { - return config.wrappingInfo.isWordWrapMinified; - } - - private _isDominatedByLongLines(config: InternalEditorOptions): boolean { - return config.wrappingInfo.isDominatedByLongLines; - } - - private _inDiffEditor(config: InternalEditorOptions): boolean { - return config.wrappingInfo.inDiffEditor; - } - public getId(): string { return ToggleWordWrapController._ID; } @@ -284,13 +272,16 @@ registerEditorContribution(ToggleWordWrapController); registerEditorAction(ToggleWordWrapAction); +const WORD_WRAP_DARK_ICON = URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg')); +const WORD_WRAP_LIGHT_ICON = URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg')); + 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/word-wrap-dark.svg')), - light: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg')) + dark: WORD_WRAP_DARK_ICON, + light: WORD_WRAP_LIGHT_ICON } }, group: 'navigation', @@ -306,8 +297,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { 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/word-wrap-dark.svg')), - light: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg')) + dark: WORD_WRAP_DARK_ICON, + light: WORD_WRAP_LIGHT_ICON } }, group: 'navigation', diff --git a/src/vs/workbench/contrib/comments/browser/commentService.ts b/src/vs/workbench/contrib/comments/browser/commentService.ts index 8cf3d7f6b8..d660861098 100644 --- a/src/vs/workbench/contrib/comments/browser/commentService.ts +++ b/src/vs/workbench/contrib/comments/browser/commentService.ts @@ -33,7 +33,7 @@ export interface IWorkspaceCommentThreadsEvent { } export interface ICommentService { - _serviceBrand: any; + _serviceBrand: undefined; readonly onDidSetResourceCommentInfos: Event; readonly onDidSetAllCommentThreads: Event; readonly onDidUpdateCommentThreads: Event; @@ -60,7 +60,7 @@ export interface ICommentService { } export class CommentService extends Disposable implements ICommentService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _onDidSetDataProvider: Emitter = this._register(new Emitter()); readonly onDidSetDataProvider: Event = this._onDidSetDataProvider.event; diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts index b35fe70763..8687b5a6b5 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts @@ -44,6 +44,7 @@ import { ICommentService } from 'vs/workbench/contrib/comments/browser/commentSe import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/commentContextKeys'; import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget'; import { SimpleCommentEditor } from './simpleCommentEditor'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export const COMMENTEDITOR_DECORATION_KEY = 'commenteditordecoration'; const COLLAPSE_ACTION_CLASS = 'expand-review-action'; @@ -128,7 +129,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._styleElement = dom.createStyleSheet(this.domNode); this._globalToDispose.add(this.themeService.onThemeChange(this._applyTheme, this)); this._globalToDispose.add(this.editor.onDidChangeConfiguration(e => { - if (e.fontInfo) { + if (e.hasChanged(EditorOption.fontInfo)) { this._applyTheme(this.themeService.getTheme()); } })); @@ -386,7 +387,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._disposables.add(this.editor.onMouseDown(e => this.onEditorMouseDown(e))); this._disposables.add(this.editor.onMouseUp(e => this.onEditorMouseUp(e))); - let headHeight = Math.ceil(this.editor.getConfiguration().lineHeight * 1.2); + let headHeight = Math.ceil(this.editor.getOption(EditorOption.lineHeight) * 1.2); this._headElement.style.height = `${headHeight}px`; this._headElement.style.lineHeight = this._headElement.style.height; @@ -692,8 +693,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget _refresh() { if (this._isExpanded && this._bodyElement) { let dimensions = dom.getClientArea(this._bodyElement); - const headHeight = Math.ceil(this.editor.getConfiguration().lineHeight * 1.2); - const lineHeight = this.editor.getConfiguration().lineHeight; + const headHeight = Math.ceil(this.editor.getOption(EditorOption.lineHeight) * 1.2); + const lineHeight = this.editor.getOption(EditorOption.lineHeight); const arrowHeight = Math.round(lineHeight / 3); const frameThickness = Math.round(lineHeight / 9) * 2; @@ -854,7 +855,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget content.push(`.monaco-editor .review-widget .body .comment-form .validation-error { color: ${errorForeground}; }`); } - const fontInfo = this.editor.getConfiguration().fontInfo; + const fontInfo = this.editor.getOption(EditorOption.fontInfo); content.push(`.monaco-editor .review-widget .body code { font-family: ${fontInfo.fontFamily}; font-size: ${fontInfo.fontSize}px; diff --git a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts index 6f81c1c882..950bfdc03e 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts @@ -37,6 +37,7 @@ import { COMMENTEDITOR_DECORATION_KEY, ReviewZoneWidget } from 'vs/workbench/con import { ctxCommentEditorFocused, SimpleCommentEditor } from 'vs/workbench/contrib/comments/browser/simpleCommentEditor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export const ID = 'editor.contrib.review'; @@ -590,18 +591,19 @@ export class ReviewController implements IEditorContribution { } this._commentInfos = commentInfos; - let lineDecorationsWidth: number = this.editor.getConfiguration().layoutInfo.decorationsWidth; + let lineDecorationsWidth: number = this.editor.getLayoutInfo().decorationsWidth; if (this._commentInfos.some(info => Boolean(info.commentingRanges && (Array.isArray(info.commentingRanges) ? info.commentingRanges : info.commentingRanges.ranges).length))) { if (!this._commentingRangeSpaceReserved) { this._commentingRangeSpaceReserved = true; let extraEditorClassName: string[] = []; - const configuredExtraClassName = this.editor.getRawConfiguration().extraEditorClassName; + const configuredExtraClassName = this.editor.getRawOptions().extraEditorClassName; if (configuredExtraClassName) { extraEditorClassName = configuredExtraClassName.split(' '); } - if (this.editor.getConfiguration().contribInfo.folding) { + const options = this.editor.getOptions(); + if (options.get(EditorOption.folding)) { lineDecorationsWidth -= 16; } lineDecorationsWidth += 9; diff --git a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts index b3851bcb9a..48c68e15ee 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts @@ -175,6 +175,7 @@ export class CommentsList extends WorkbenchAsyncDataTree { ]; super( + 'CommentsTree', container, delegate, renderers, diff --git a/src/vs/workbench/contrib/customEditor/browser/commands.ts b/src/vs/workbench/contrib/customEditor/browser/commands.ts new file mode 100644 index 0000000000..a5f1aab44c --- /dev/null +++ b/src/vs/workbench/contrib/customEditor/browser/commands.ts @@ -0,0 +1,108 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Schemas } from 'vs/base/common/network'; +import { URI } from 'vs/base/common/uri'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import * as nls from 'vs/nls'; +import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { IListService } from 'vs/platform/list/browser/listService'; +import { IEditorCommandsContext } from 'vs/workbench/common/editor'; +import { ResourceContextKey } from 'vs/workbench/common/resources'; +import { ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; +import { getMultiSelectedResources } from 'vs/workbench/contrib/files/browser/files'; +import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; + +const viewCategory = nls.localize('viewCategory', "View"); + +// #region Open With + +const OPEN_WITH_COMMAND_ID = 'openWith'; +const OPEN_WITH_TITLE = { value: nls.localize('openWith.title', 'Open With'), original: 'Open With' }; + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: OPEN_WITH_COMMAND_ID, + weight: KeybindingWeight.WorkbenchContrib, + when: EditorContextKeys.focus.toNegated(), + handler: async (accessor: ServicesAccessor, resource: URI | object) => { + const editorService = accessor.get(IEditorService); + const resources = getMultiSelectedResources(resource, accessor.get(IListService), editorService); + const targetResource = resources[0]; + if (!targetResource) { + return undefined; // {{SQL CARBON EDIT}} strict-null-check + } + return accessor.get(ICustomEditorService).promptOpenWith(targetResource, undefined, undefined); + } +}); + +MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { + group: 'navigation', + order: 20, + command: { + id: OPEN_WITH_COMMAND_ID, + title: OPEN_WITH_TITLE, + }, + when: ResourceContextKey.Scheme.isEqualTo(Schemas.file) +}); + +// #endregion + +// #region Reopen With + +const REOPEN_WITH_COMMAND_ID = 'reOpenWith'; +const REOPEN_WITH_TITLE = { value: nls.localize('reopenWith.title', 'Reopen With'), original: 'Reopen With' }; + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: REOPEN_WITH_COMMAND_ID, + weight: KeybindingWeight.WorkbenchContrib, + when: undefined, + handler: async (accessor: ServicesAccessor, resource?: URI, editorContext?: IEditorCommandsContext) => { + const customEditorService = accessor.get(ICustomEditorService); + const editorService = accessor.get(IEditorService); + const editorGroupService = accessor.get(IEditorGroupsService); + + let group: IEditorGroup | undefined; + if (editorContext) { + group = editorGroupService.getGroup(editorContext.groupId); + } else if (!resource) { + if (editorService.activeEditor) { + resource = editorService.activeEditor.getResource(); + group = editorGroupService.activeGroup; + } + } + + if (!resource) { + return; + } + + // Make sure the context menu has been dismissed before we prompt. + // Otherwise with webviews, we will sometimes close the prompt instantly when the webview is + // refocused by the workbench + setTimeout(() => { + customEditorService.promptOpenWith(resource!, undefined, group); + }, 10); + } +}); + +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { + order: 40, + command: { + id: REOPEN_WITH_COMMAND_ID, + title: REOPEN_WITH_TITLE, + } +}); + +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { + command: { + id: REOPEN_WITH_COMMAND_ID, + title: REOPEN_WITH_TITLE, + category: viewCategory, + } +}); + +// #endregion diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts new file mode 100644 index 0000000000..182b391c00 --- /dev/null +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts @@ -0,0 +1,109 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { memoize } from 'vs/base/common/decorators'; +import { UnownedDisposable } from 'vs/base/common/lifecycle'; +import { basename } from 'vs/base/common/path'; +import { URI } from 'vs/base/common/uri'; +import { IEditorModel } from 'vs/platform/editor/common/editor'; +import { ILabelService } from 'vs/platform/label/common/label'; +import { IEditorInput, Verbosity } from 'vs/workbench/common/editor'; +import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/webview'; +import { WebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; +import { IWebviewEditorService } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { WebviewEditorState } from 'vs/editor/common/modes'; + +export class CustomFileEditorInput extends WebviewEditorInput { + + public static typeId = 'workbench.editors.webviewEditor'; + + private name?: string; + private _hasResolved = false; + private readonly _editorResource: URI; + private _state = WebviewEditorState.Readonly; + + constructor( + resource: URI, + viewType: string, + id: string, + webview: UnownedDisposable, + @ILabelService + private readonly labelService: ILabelService, + @IWebviewEditorService + private readonly _webviewEditorService: IWebviewEditorService, + @IExtensionService + private readonly _extensionService: IExtensionService + ) { + super(id, viewType, '', undefined, webview); + this._editorResource = resource; + } + + public getTypeId(): string { + return CustomFileEditorInput.typeId; + } + + public getResource(): URI { + return this._editorResource; + } + + getName(): string { + if (!this.name) { + this.name = basename(this.labelService.getUriLabel(this.getResource())); + } + return this.name; + } + + matches(other: IEditorInput): boolean { + return this === other || (other instanceof CustomFileEditorInput + && this.viewType === other.viewType + && this.getResource().toString() === other.getResource().toString()); + } + + @memoize + private get shortTitle(): string { + return this.getName(); + } + + @memoize + private get mediumTitle(): string { + return this.labelService.getUriLabel(this.getResource(), { relative: true }); + } + + @memoize + private get longTitle(): string { + return this.labelService.getUriLabel(this.getResource()); + } + + getTitle(verbosity?: Verbosity): string { + switch (verbosity) { + case Verbosity.SHORT: + return this.shortTitle; + default: + case Verbosity.MEDIUM: + return this.mediumTitle; + case Verbosity.LONG: + return this.longTitle; + } + } + + public async resolve(): Promise { + if (!this._hasResolved) { + this._hasResolved = true; + this._extensionService.activateByEvent(`onWebviewEditor:${this.viewType}`); + await this._webviewEditorService.resolveWebview(this); + } + return super.resolve(); + } + + public setState(newState: WebviewEditorState): void { + this._state = newState; + this._onDidChangeDirty.fire(); + } + + public isDirty() { + return this._state === WebviewEditorState.Dirty; + } +} diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts new file mode 100644 index 0000000000..b0d6506c92 --- /dev/null +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { UnownedDisposable } from 'vs/base/common/lifecycle'; +import { URI } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { CustomFileEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput'; +import { WebviewEditorInputFactory } from 'vs/workbench/contrib/webview/browser/webviewEditorInputFactory'; +import { IWebviewEditorService } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; + +export class CustomEditoInputFactory extends WebviewEditorInputFactory { + + public static readonly ID = CustomFileEditorInput.typeId; + + public constructor( + @IInstantiationService private readonly _instantiationService: IInstantiationService, + @IWebviewEditorService private readonly webviewService: IWebviewEditorService, + ) { + super(webviewService); + } + + public serialize(input: CustomFileEditorInput): string | undefined { + const data = { + ...this.toJson(input), + editorResource: input.getResource().toJSON() + }; + + try { + return JSON.stringify(data); + } catch { + return undefined; + } + } + + public deserialize( + _instantiationService: IInstantiationService, + serializedEditorInput: string + ): CustomFileEditorInput { + const data = this.fromJson(serializedEditorInput); + const webviewInput = this.webviewService.reviveWebview(generateUuid(), data.viewType, data.title, data.iconPath, data.state, data.options, data.extensionLocation ? { + location: data.extensionLocation, + id: data.extensionId + } : undefined, data.group); + + const customInput = this._instantiationService.createInstance(CustomFileEditorInput, URI.from((data as any).editorResource), data.viewType, generateUuid(), new UnownedDisposable(webviewInput.webview)); + if (typeof data.group === 'number') { + customInput.updateGroup(data.group); + } + return customInput; + } +} diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts new file mode 100644 index 0000000000..4f25896b21 --- /dev/null +++ b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts @@ -0,0 +1,231 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { coalesce, distinct } from 'vs/base/common/arrays'; +import * as glob from 'vs/base/common/glob'; +import { UnownedDisposable } from 'vs/base/common/lifecycle'; +import { basename } from 'vs/base/common/resources'; +import { withNullAsUndefined } from 'vs/base/common/types'; +import { URI } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; +import * as nls from 'vs/nls'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { EditorOptions, IEditor, IEditorInput } from 'vs/workbench/common/editor'; +import { webviewEditorsExtensionPoint } from 'vs/workbench/contrib/customEditor/browser/extensionPoint'; +import { CustomEditorDiscretion, CustomEditorInfo, CustomEditorSelector, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; +import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; +import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview'; +import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/editor/common/editorService'; +import { CustomFileEditorInput } from './customEditorInput'; + +export class CustomEditorService implements ICustomEditorService { + _serviceBrand: any; + + private readonly customEditors = new Map(); + + constructor( + @IConfigurationService private readonly configurationService: IConfigurationService, + @IEditorService private readonly editorService: IEditorService, + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IQuickInputService private readonly quickInputService: IQuickInputService, + @IWebviewService private readonly webviewService: IWebviewService, + ) { + webviewEditorsExtensionPoint.setHandler(extensions => { + for (const extension of extensions) { + for (const webviewEditorContribution of extension.value) { + this.customEditors.set(webviewEditorContribution.viewType, { + id: webviewEditorContribution.viewType, + displayName: webviewEditorContribution.displayName, + selector: webviewEditorContribution.selector || [], + discretion: webviewEditorContribution.discretion || CustomEditorDiscretion.default, + }); + } + } + }); + } + + public getContributedCustomEditors(resource: URI): readonly CustomEditorInfo[] { + return Array.from(this.customEditors.values()).filter(customEditor => + customEditor.selector.some(selector => matches(selector, resource))); + } + + public getUserConfiguredCustomEditors(resource: URI): readonly CustomEditorInfo[] { + const rawAssociations = this.configurationService.getValue(customEditorsAssociationsKey) || []; + return coalesce(rawAssociations + .filter(association => matches(association, resource)) + .map(association => this.customEditors.get(association.viewType))); + } + + public async promptOpenWith( + resource: URI, + options?: ITextEditorOptions, + group?: IEditorGroup, + ): Promise { + const customEditors = distinct([ + ...this.getUserConfiguredCustomEditors(resource), + ...this.getContributedCustomEditors(resource), + ], editor => editor.id); + + const defaultEditorId = 'default'; + const pick = await this.quickInputService.pick([ + { + label: nls.localize('promptOpenWith.defaultEditor', "Default built-in editor"), + id: defaultEditorId, + }, + ...customEditors.map((editorDescriptor): IQuickPickItem => ({ + label: editorDescriptor.displayName, + id: editorDescriptor.id, + })) + ], { + placeHolder: nls.localize('promptOpenWith.placeHolder', "Select editor to use for '{0}'...", basename(resource)), + }); + + if (!pick) { + return undefined; // {{SQL CARBON EDIT}} strict-null-check + } + + if (pick.id === defaultEditorId) { + const fileInput = this.instantiationService.createInstance(FileEditorInput, resource, undefined, undefined); + return this.openEditorForResource(resource, fileInput, { ...options, ignoreOverrides: true }, group); + } else { + return this.openWith(resource, pick.id!, options, group); + } + } + + public openWith( + resource: URI, + viewType: string, + options?: ITextEditorOptions, + group?: IEditorGroup, + ): Promise { + if (!this.customEditors.has(viewType)) { + return this.promptOpenWith(resource, options, group); + } + + const id = generateUuid(); + const webview = this.webviewService.createWebviewEditorOverlay(id, {}, {}); + const input = this.instantiationService.createInstance(CustomFileEditorInput, resource, viewType, id, new UnownedDisposable(webview)); + if (group) { + input.updateGroup(group!.id); + } + return this.openEditorForResource(resource, input, options, group); + } + + private async openEditorForResource( + resource: URI, + input: IEditorInput, + options?: IEditorOptions, + group?: IEditorGroup + ): Promise { + if (group) { + const existingEditors = group.editors.filter(editor => editor.getResource() && editor.getResource()!.toString() === resource.toString()); + if (existingEditors.length) { + await this.editorService.replaceEditors([{ + editor: existingEditors[0], + replacement: input, + options: options ? EditorOptions.create(options) : undefined, + }], group); + } + } + return this.editorService.openEditor(input, options, group); + } +} + +export const customEditorsAssociationsKey = 'workbench.experimental.editorAssociations'; + +export type CustomEditorsAssociations = readonly (CustomEditorSelector & { readonly viewType: string })[]; + +export class CustomEditorContribution implements IWorkbenchContribution { + constructor( + @IEditorService private readonly editorService: IEditorService, + @ICustomEditorService private readonly customEditorService: ICustomEditorService, + ) { + this.editorService.overrideOpenEditor((editor, options, group) => this.onEditorOpening(editor, options, group)); + } + + private onEditorOpening( + editor: IEditorInput, + options: ITextEditorOptions | undefined, + group: IEditorGroup + ): IOpenEditorOverride | undefined { + if (editor instanceof CustomFileEditorInput) { + return undefined; // {{SQL CARBON EDIT}} strict-null-check + } + + const resource = editor.getResource(); + if (!resource) { + return undefined; // {{SQL CARBON EDIT}} strict-null-check + } + + const userConfiguredEditors = this.customEditorService.getUserConfiguredCustomEditors(resource); + const contributedEditors = this.customEditorService.getContributedCustomEditors(resource); + + if (!userConfiguredEditors.length) { + if (!contributedEditors.length) { + return undefined; // {{SQL CARBON EDIT}} strict-null-check + } + + const defaultEditors = contributedEditors.filter(editor => editor.discretion === CustomEditorDiscretion.default); + if (defaultEditors.length === 1) { + return { + override: this.customEditorService.openWith(resource, defaultEditors[0].id, options, group), + }; + } + } + + for (const input of group.editors) { + if (input instanceof CustomFileEditorInput && input.getResource().toString() === resource.toString()) { + return { + override: group.openEditor(input, options).then(withNullAsUndefined) + }; + } + } + + if (userConfiguredEditors.length) { + return { + override: this.customEditorService.openWith(resource, userConfiguredEditors[0].id, options, group), + }; + } + + // Open default editor but prompt user to see if they wish to use a custom one instead + return { + override: (async () => { + const standardEditor = await this.editorService.openEditor(editor, { ...options, ignoreOverrides: true }, group); + const selectedEditor = await this.customEditorService.promptOpenWith(resource, options, group); + if (selectedEditor && selectedEditor.input) { + await group.replaceEditors([{ + editor, + replacement: selectedEditor.input + }]); + return selectedEditor; + } + + return standardEditor; + })() + }; + } +} + +function matches(selector: CustomEditorSelector, resource: URI): boolean { + if (!selector.filenamePattern && !selector.scheme) { + return false; + } + if (selector.filenamePattern) { + if (!glob.match(selector.filenamePattern.toLowerCase(), basename(resource).toLowerCase())) { + return false; + } + } + if (selector.scheme) { + if (resource.scheme !== selector.scheme) { + return false; + } + } + return true; +} diff --git a/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts b/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts new file mode 100644 index 0000000000..86eabe8a2f --- /dev/null +++ b/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts @@ -0,0 +1,84 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import * as nls from 'vs/nls'; +import { CustomEditorDiscretion, CustomEditorSelector } from 'vs/workbench/contrib/customEditor/common/customEditor'; +import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { languagesExtPoint } from 'vs/workbench/services/mode/common/workbenchModeService'; + +namespace WebviewEditorContribution { + export const viewType = 'viewType'; + export const displayName = 'displayName'; + export const selector = 'selector'; + export const discretion = 'discretion'; +} + +interface IWebviewEditorsExtensionPoint { + readonly [WebviewEditorContribution.viewType]: string; + readonly [WebviewEditorContribution.displayName]: string; + readonly [WebviewEditorContribution.selector]?: readonly CustomEditorSelector[]; + readonly [WebviewEditorContribution.discretion]?: CustomEditorDiscretion; +} + +const webviewEditorsContribution: IJSONSchema = { + description: nls.localize('contributes.webviewEditors', 'Contributes webview editors.'), + type: 'array', + defaultSnippets: [{ body: [{ viewType: '', displayName: '' }] }], + items: { + type: 'object', + required: [ + WebviewEditorContribution.viewType, + WebviewEditorContribution.displayName, + WebviewEditorContribution.selector, + ], + properties: { + [WebviewEditorContribution.viewType]: { + type: 'string', + description: nls.localize('contributes.viewType', 'Unique identifier of the custom editor.'), + }, + [WebviewEditorContribution.displayName]: { + type: 'string', + description: nls.localize('contributes.displayName', 'Name of the custom editor displayed to users.'), + }, + [WebviewEditorContribution.selector]: { + type: 'array', + description: nls.localize('contributes.selector', 'Set of globs that the custom editor is enabled for.'), + items: { + type: 'object', + properties: { + filenamePattern: { + type: 'string', + description: nls.localize('contributes.selector.filenamePattern', 'Glob that the custom editor is enabled for.'), + }, + scheme: { + type: 'string', + description: nls.localize('contributes.selector.scheme', 'File scheme that the custom editor is enabled for.'), + } + } + } + }, + [WebviewEditorContribution.discretion]: { + type: 'string', + description: nls.localize('contributes.discretion', 'Controls when the custom editor is used. May be overridden by users.'), + enum: [ + CustomEditorDiscretion.default, + CustomEditorDiscretion.option + ], + enumDescriptions: [ + nls.localize('contributes.discretion.default', 'Editor is automatically used for a resource if no other default custom editors are registered for it.'), + nls.localize('contributes.discretion.option', 'Editor is not automatically used but can be selected by a user.'), + ], + default: 'default' + } + } + } +}; + +export const webviewEditorsExtensionPoint = ExtensionsRegistry.registerExtensionPoint({ + extensionPoint: 'webviewEditors', + deps: [languagesExtPoint], + jsonSchema: webviewEditorsContribution +}); diff --git a/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts b/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts new file mode 100644 index 0000000000..206730c896 --- /dev/null +++ b/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts @@ -0,0 +1,69 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { EditorDescriptor, Extensions as EditorExtensions, IEditorRegistry } from 'vs/workbench/browser/editor'; +import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; +import { Extensions as EditorInputExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; +import { CustomEditoInputFactory } from 'vs/workbench/contrib/customEditor/browser/customEditorInputFactory'; +import { ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; +import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor'; +import './commands'; +import { CustomFileEditorInput } from './customEditorInput'; +import { CustomEditorContribution, customEditorsAssociationsKey, CustomEditorService } from './customEditors'; + +registerSingleton(ICustomEditorService, CustomEditorService); + +Registry.as(WorkbenchExtensions.Workbench) + .registerWorkbenchContribution(CustomEditorContribution, LifecyclePhase.Starting); + +Registry.as(EditorExtensions.Editors).registerEditor( + new EditorDescriptor( + WebviewEditor, + WebviewEditor.ID, + 'Webview Editor', + ), [ + new SyncDescriptor(CustomFileEditorInput) +]); + +Registry.as(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory( + CustomEditoInputFactory.ID, + CustomEditoInputFactory); + +Registry.as(ConfigurationExtensions.Configuration) + .registerConfiguration({ + 'id': 'workbench', + 'order': 7, + 'title': nls.localize('workbenchConfigurationTitle', "Workbench"), + 'type': 'object', + 'properties': { + [customEditorsAssociationsKey]: { + type: 'array', + markdownDescription: nls.localize('editor.editorAssociations', "Configure which editor to use for a resource."), + items: { + type: 'object', + properties: { + 'viewType': { + type: 'string', + description: nls.localize('editor.editorAssociations.viewType', "Editor view type."), + }, + 'scheme': { + type: 'string', + description: nls.localize('editor.editorAssociations.scheme', "Uri scheme the editor should be used for."), + }, + 'filenamePattern': { + type: 'string', + description: nls.localize('editor.editorAssociations.filenamePattern', "Glob pattern the the editor should be used for."), + } + } + } + } + } + }); diff --git a/src/vs/workbench/contrib/customEditor/common/customEditor.ts b/src/vs/workbench/contrib/customEditor/common/customEditor.ts new file mode 100644 index 0000000000..9298b62789 --- /dev/null +++ b/src/vs/workbench/contrib/customEditor/common/customEditor.ts @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { URI } from 'vs/base/common/uri'; +import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IEditor } from 'vs/workbench/common/editor'; +import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; + + +export const ICustomEditorService = createDecorator('customEditorService'); + +export interface ICustomEditorService { + _serviceBrand: any; + + getContributedCustomEditors(resource: URI): readonly CustomEditorInfo[]; + getUserConfiguredCustomEditors(resource: URI): readonly CustomEditorInfo[]; + + openWith(resource: URI, customEditorViewType: string, options?: ITextEditorOptions, group?: IEditorGroup): Promise; + promptOpenWith(resource: URI, options?: ITextEditorOptions, group?: IEditorGroup): Promise; +} + +export const enum CustomEditorDiscretion { + default = 'default', + option = 'option', +} + +export interface CustomEditorSelector { + readonly scheme?: string; + readonly filenamePattern?: string; +} + +export interface CustomEditorInfo { + readonly id: string; + readonly displayName: string; + readonly discretion: CustomEditorDiscretion; + readonly selector: readonly CustomEditorSelector[]; +} diff --git a/src/vs/workbench/contrib/debug/browser/baseDebugView.ts b/src/vs/workbench/contrib/debug/browser/baseDebugView.ts index f358394759..013edf7a16 100644 --- a/src/vs/workbench/contrib/debug/browser/baseDebugView.ts +++ b/src/vs/workbench/contrib/debug/browser/baseDebugView.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; -import { IExpression, IDebugService } from 'vs/workbench/contrib/debug/common/debug'; +import { IExpression, IDebugService, IExpressionContainer } from 'vs/workbench/contrib/debug/common/debug'; import { Expression, Variable, ExpressionContainer } from 'vs/workbench/contrib/debug/common/debugModel'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IInputValidationOptions, InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; @@ -16,6 +16,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { HighlightedLabel, IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { FuzzyScore, createMatches } from 'vs/base/common/filters'; +import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector'; export const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024; export const twistiePixels = 20; @@ -29,6 +30,7 @@ export interface IRenderValueOptions { maxValueLength?: number; showHover?: boolean; colorize?: boolean; + linkDetector?: LinkDetector; } export interface IVariableTemplateData { @@ -50,7 +52,7 @@ export function replaceWhitespace(value: string): string { return value.replace(/[\n\r\t]/g, char => map[char]); } -export function renderExpressionValue(expressionOrValue: IExpression | string, container: HTMLElement, options: IRenderValueOptions): void { +export function renderExpressionValue(expressionOrValue: IExpressionContainer | string, container: HTMLElement, options: IRenderValueOptions): void { let value = typeof expressionOrValue === 'string' ? expressionOrValue : expressionOrValue.value; // remove stale classes @@ -83,16 +85,22 @@ export function renderExpressionValue(expressionOrValue: IExpression | string, c value = value.substr(0, options.maxValueLength) + '...'; } if (value && !options.preserveWhitespace) { - container.textContent = replaceWhitespace(value); + value = replaceWhitespace(value); } else { - container.textContent = value || ''; + value = value || ''; + } + if (options.linkDetector) { + container.textContent = ''; + container.appendChild(options.linkDetector.handleLinks(value)); + } else { + container.textContent = value; } if (options.showHover) { container.title = value || ''; } } -export function renderVariable(variable: Variable, data: IVariableTemplateData, showChanged: boolean, highlights: IHighlight[]): void { +export function renderVariable(variable: Variable, data: IVariableTemplateData, showChanged: boolean, highlights: IHighlight[], linkDetector?: LinkDetector): void { if (variable.available) { let text = replaceWhitespace(variable.name); if (variable.value && typeof variable.name === 'string') { @@ -109,7 +117,8 @@ export function renderVariable(variable: Variable, data: IVariableTemplateData, maxValueLength: MAX_VALUE_RENDER_LENGTH_IN_VIEWLET, preserveWhitespace: false, showHover: true, - colorize: true + colorize: true, + linkDetector }); } @@ -209,16 +218,19 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer, index: number, data: IExpressionTemplateData): void { const { element } = node; if (element === this.debugService.getViewModel().getSelectedExpression()) { - data.enableInputBox(element, this.getInputBoxOptions(element)); - } else { - this.renderExpression(element, data, createMatches(node.filterData)); + const options = this.getInputBoxOptions(element); + if (options) { + data.enableInputBox(element, options); + return; + } } + this.renderExpression(element, data, createMatches(node.filterData)); } protected abstract renderExpression(expression: IExpression, data: IExpressionTemplateData, highlights: IHighlight[]): void; - protected abstract getInputBoxOptions(expression: IExpression): IInputBoxOptions; + protected abstract getInputBoxOptions(expression: IExpression): IInputBoxOptions | undefined; disposeTemplate(templateData: IExpressionTemplateData): void { dispose(templateData.toDispose); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts b/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts index 3d8701c5ca..651d9dde79 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts @@ -39,13 +39,13 @@ import { onUnexpectedError } from 'vs/base/common/errors'; const $ = dom.$; const IPrivateBreakpointWidgetService = createDecorator('privateBreakopintWidgetService'); export interface IPrivateBreakpointWidgetService { - _serviceBrand: any; + _serviceBrand: undefined; close(success: boolean): void; } const DECORATION_KEY = 'breakpointwidgetdecoration'; export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWidgetService { - _serviceBrand: any; + _serviceBrand: undefined; private selectContainer!: HTMLElement; private input!: IActiveCodeEditor; diff --git a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts index fa94de5165..1eca288468 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts @@ -70,23 +70,23 @@ export class BreakpointsView extends ViewletPanel { dom.addClass(container, 'debug-breakpoints'); const delegate = new BreakpointsDelegate(this.debugService); - this.list = this.instantiationService.createInstance(WorkbenchList, container, delegate, [ + this.list = this.instantiationService.createInstance(WorkbenchList, 'Breakpoints', container, delegate, [ this.instantiationService.createInstance(BreakpointsRenderer), new ExceptionBreakpointsRenderer(this.debugService), this.instantiationService.createInstance(FunctionBreakpointsRenderer), this.instantiationService.createInstance(DataBreakpointsRenderer), new FunctionBreakpointInputRenderer(this.debugService, this.contextViewService, this.themeService) ], { - identityProvider: { getId: (element: IEnablement) => element.getId() }, - multipleSelectionSupport: false, - keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IEnablement) => e }, - ariaProvider: { - getSetSize: (_: IEnablement, index: number, listLength: number) => listLength, - getPosInSet: (_: IEnablement, index: number) => index, - getRole: (breakpoint: IEnablement) => 'checkbox', - isChecked: (breakpoint: IEnablement) => breakpoint.enabled - } - }); + identityProvider: { getId: (element: IEnablement) => element.getId() }, + multipleSelectionSupport: false, + keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IEnablement) => e }, + ariaProvider: { + getSetSize: (_: IEnablement, index: number, listLength: number) => listLength, + getPosInSet: (_: IEnablement, index: number) => index, + getRole: (breakpoint: IEnablement) => 'checkbox', + isChecked: (breakpoint: IEnablement) => breakpoint.enabled + } + }); CONTEXT_BREAKPOINTS_FOCUSED.bindTo(this.list.contextKeyService); @@ -445,7 +445,7 @@ class FunctionBreakpointsRenderer implements IListRenderer; private contributedContextMenu: IMenu; private parentSessionToExpand = new Set(); + private selectionNeedsUpdate = false; constructor( private options: IViewletViewOptions, @@ -86,7 +91,10 @@ export class CallStackView extends ViewletPanel { this.tree.updateChildren().then(() => { this.parentSessionToExpand.forEach(s => this.tree.expand(s)); this.parentSessionToExpand.clear(); - this.updateTreeSelection(); + if (this.selectionNeedsUpdate) { + this.selectionNeedsUpdate = false; + this.updateTreeSelection(); + } }); }, 50); } @@ -105,48 +113,48 @@ export class CallStackView extends ViewletPanel { const treeContainer = renderViewTree(container); this.dataSource = new CallStackDataSource(this.debugService); - this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, treeContainer, new CallStackDelegate(), [ - new SessionsRenderer(), - new ThreadsRenderer(), + this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'CallStackView', treeContainer, new CallStackDelegate(), [ + new SessionsRenderer(this.instantiationService), + new ThreadsRenderer(this.instantiationService), this.instantiationService.createInstance(StackFramesRenderer), new ErrorsRenderer(), new LoadMoreRenderer(), new ShowMoreRenderer() ], this.dataSource, { - accessibilityProvider: new CallStackAccessibilityProvider(), - ariaLabel: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'callStackAriaLabel' }, "Debug Call Stack"), - identityProvider: { - getId: (element: CallStackItem) => { - if (typeof element === 'string') { - return element; - } - if (element instanceof Array) { - return `showMore ${element[0].getId()}`; - } - - return element.getId(); + accessibilityProvider: new CallStackAccessibilityProvider(), + ariaLabel: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'callStackAriaLabel' }, "Debug Call Stack"), + identityProvider: { + getId: (element: CallStackItem) => { + if (typeof element === 'string') { + return element; } - }, - keyboardNavigationLabelProvider: { - getKeyboardNavigationLabel: (e: CallStackItem) => { - if (isDebugSession(e)) { - return e.getLabel(); - } - if (e instanceof Thread) { - return `${e.name} ${e.stateLabel}`; - } - if (e instanceof StackFrame || typeof e === 'string') { - return e; - } - if (e instanceof ThreadAndSessionIds) { - return LoadMoreRenderer.LABEL; - } - - return nls.localize('showMoreStackFrames2', "Show More Stack Frames"); + if (element instanceof Array) { + return `showMore ${element[0].getId()}`; } - }, - expandOnlyOnTwistieClick: true - }); + + return element.getId(); + } + }, + keyboardNavigationLabelProvider: { + getKeyboardNavigationLabel: (e: CallStackItem) => { + if (isDebugSession(e)) { + return e.getLabel(); + } + if (e instanceof Thread) { + return `${e.name} ${e.stateLabel}`; + } + if (e instanceof StackFrame || typeof e === 'string') { + return e; + } + if (e instanceof ThreadAndSessionIds) { + return LoadMoreRenderer.LABEL; + } + + return nls.localize('showMoreStackFrames2', "Show More Stack Frames"); + } + }, + expandOnlyOnTwistieClick: true + }); this.tree.setInput(this.debugService.getModel()).then(undefined, onUnexpectedError); @@ -201,8 +209,8 @@ export class CallStackView extends ViewletPanel { this.onCallStackChangeScheduler.schedule(); } })); - const onCallStackChange = Event.any(this.debugService.getViewModel().onDidFocusStackFrame, this.debugService.getViewModel().onDidFocusSession); - this._register(onCallStackChange(() => { + const onFocusChange = Event.any(this.debugService.getViewModel().onDidFocusStackFrame, this.debugService.getViewModel().onDidFocusSession); + this._register(onFocusChange(() => { if (this.ignoreFocusStackFrameEvent) { return; } @@ -210,6 +218,10 @@ export class CallStackView extends ViewletPanel { this.needsRefresh = true; return; } + if (this.onCallStackChangeScheduler.isScheduled()) { + this.selectionNeedsUpdate = true; + return; + } this.updateTreeSelection(); })); @@ -227,6 +239,7 @@ export class CallStackView extends ViewletPanel { })); this._register(this.debugService.onDidNewSession(s => { + this._register(s.onDidChangeName(() => this.tree.rerender(s))); if (s.parentSession) { // Auto expand sessions that have sub sessions this.parentSessionToExpand.add(s.parentSession); @@ -334,6 +347,7 @@ interface IThreadTemplateData { state: HTMLElement; stateLabel: HTMLSpanElement; label: HighlightedLabel; + actionBar: ActionBar; } interface ISessionTemplateData { @@ -342,6 +356,7 @@ interface ISessionTemplateData { state: HTMLElement; stateLabel: HTMLSpanElement; label: HighlightedLabel; + actionBar: ActionBar; } interface IErrorTemplateData { @@ -363,6 +378,10 @@ interface IStackFrameTemplateData { class SessionsRenderer implements ITreeRenderer { static readonly ID = 'session'; + constructor( + private readonly instantiationService: IInstantiationService + ) { } + get templateId(): string { return SessionsRenderer.ID; } @@ -373,28 +392,35 @@ class SessionsRenderer implements ITreeRenderer, index: number, data: ISessionTemplateData): void { + renderElement(element: ITreeNode, _: number, data: ISessionTemplateData): void { const session = element.element; data.session.title = nls.localize({ key: 'session', comment: ['Session is a noun'] }, "Session"); data.label.set(session.getLabel(), createMatches(element.filterData)); const stoppedThread = session.getAllThreads().filter(t => t.stopped).pop(); + data.actionBar.clear(); + const actions = getActions(this.instantiationService, element.element); + data.actionBar.push(actions, { icon: true, label: false }); + data.stateLabel.textContent = stoppedThread ? nls.localize('paused', "Paused") : nls.localize({ key: 'running', comment: ['indicates state'] }, "Running"); } disposeTemplate(templateData: ISessionTemplateData): void { - // noop + templateData.actionBar.dispose(); } } class ThreadsRenderer implements ITreeRenderer { static readonly ID = 'thread'; + constructor(private readonly instantiationService: IInstantiationService) { } + get templateId(): string { return ThreadsRenderer.ID; } @@ -405,8 +431,9 @@ class ThreadsRenderer implements ITreeRenderer, index: number, data: IThreadTemplateData): void { @@ -414,10 +441,14 @@ class ThreadsRenderer implements ITreeRenderer { + return [ + thread.stopped ? instantiationService.createInstance(ContinueAction, thread) : instantiationService.createInstance(PauseAction, thread), + instantiationService.createInstance(StepOverAction, thread), + instantiationService.createInstance(StepIntoAction, thread), + instantiationService.createInstance(StepOutAction, thread) + ]; + }; + + if (element instanceof Thread) { + return getThreadActions(element); + } + + const session = element; + const stopOrDisconectAction = isSessionAttach(session) ? instantiationService.createInstance(DisconnectAction, session) : instantiationService.createInstance(StopAction, session); + const restartAction = instantiationService.createInstance(RestartAction, session); + const threads = session.getAllThreads(); + if (threads.length === 1) { + return getThreadActions(threads[0]).concat([ + restartAction, + stopOrDisconectAction + ]); + } + + return [ + restartAction, + stopOrDisconectAction + ]; +} + + +class StopAction extends Action { + + constructor( + private readonly session: IDebugSession, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${STOP_ID}`, STOP_LABEL, 'debug-action stop'); + } + + public run(): Promise { + return this.commandService.executeCommand(STOP_ID, this.session.getId(), this.session); + } +} + +class DisconnectAction extends Action { + + constructor( + private readonly session: IDebugSession, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${DISCONNECT_ID}`, DISCONNECT_LABEL, 'debug-action disconnect'); + } + + public run(): Promise { + return this.commandService.executeCommand(DISCONNECT_ID, this.session.getId(), this.session); + } +} + +class RestartAction extends Action { + + constructor( + private readonly session: IDebugSession, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${RESTART_SESSION_ID}`, RESTART_LABEL, 'debug-action restart'); + } + + public run(): Promise { + return this.commandService.executeCommand(RESTART_SESSION_ID, this.session.getId(), this.session); + } +} + +class StepOverAction extends Action { + + constructor( + private readonly thread: IThread, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${STEP_OVER_ID}`, STEP_OVER_LABEL, 'debug-action step-over', thread.stopped); + } + + public run(): Promise { + return this.commandService.executeCommand(STEP_OVER_ID, this.thread.threadId, this.thread); + } +} + +class StepIntoAction extends Action { + + constructor( + private readonly thread: IThread, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${STEP_INTO_ID}`, STEP_INTO_LABEL, 'debug-action step-into', thread.stopped); + } + + public run(): Promise { + return this.commandService.executeCommand(STEP_INTO_ID, this.thread.threadId, this.thread); + } +} + +class StepOutAction extends Action { + + constructor( + private readonly thread: IThread, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${STEP_OUT_ID}`, STEP_OUT_LABEL, 'debug-action step-out', thread.stopped); + } + + public run(): Promise { + return this.commandService.executeCommand(STEP_OUT_ID, this.thread.threadId, this.thread); + } +} + +class PauseAction extends Action { + + constructor( + private readonly thread: IThread, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${PAUSE_ID}`, PAUSE_LABEL, 'debug-action pause', !thread.stopped); + } + + public run(): Promise { + return this.commandService.executeCommand(PAUSE_ID, this.thread.threadId, this.thread); + } +} + +class ContinueAction extends Action { + + constructor( + private readonly thread: IThread, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${CONTINUE_ID}`, CONTINUE_LABEL, 'debug-action continue', thread.stopped); + } + + public run(): Promise { + return this.commandService.executeCommand(CONTINUE_ID, this.thread.threadId, this.thread); + } +} diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index dbd946331c..ba455c72fa 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -29,7 +29,7 @@ import { StartAction, AddFunctionBreakpointAction, ConfigureAction, DisableAllBr import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar'; import * as service from 'vs/workbench/contrib/debug/browser/debugService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { registerCommands, ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, REVERSE_CONTINUE_ID, STEP_BACK_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID } from 'vs/workbench/contrib/debug/browser/debugCommands'; +import { registerCommands, ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, REVERSE_CONTINUE_ID, STEP_BACK_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands'; import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider'; import { IViewsRegistry, Extensions as ViewExtensions } from 'vs/workbench/common/views'; @@ -48,6 +48,7 @@ import { WatchExpressionsView } from 'vs/workbench/contrib/debug/browser/watchEx import { VariablesView } from 'vs/workbench/contrib/debug/browser/variablesView'; import { ClearReplAction, Repl } from 'vs/workbench/contrib/debug/browser/repl'; import { DebugContentProvider } from 'vs/workbench/contrib/debug/common/debugContentProvider'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; class OpenDebugViewletAction extends ShowViewletAction { public static readonly ID = VIEWLET_ID; @@ -148,23 +149,16 @@ const registerDebugCommandPaletteItem = (id: string, title: string, when?: Conte } }); }; -const restartLabel = nls.localize('restartDebug', "Restart"); -const stepOverLabel = nls.localize('stepOverDebug', "Step Over"); -const stepIntoLabel = nls.localize('stepIntoDebug', "Step Into"); -const stepOutLabel = nls.localize('stepOutDebug', "Step Out"); -const pauseLabel = nls.localize('pauseDebug', "Pause"); -const disconnectLabel = nls.localize('disconnect', "Disconnect"); -const stopLabel = nls.localize('stop', "Stop"); -const continueLabel = nls.localize('continueDebug', "Continue"); -registerDebugCommandPaletteItem(RESTART_SESSION_ID, restartLabel); + +registerDebugCommandPaletteItem(RESTART_SESSION_ID, RESTART_LABEL); registerDebugCommandPaletteItem(TERMINATE_THREAD_ID, nls.localize('terminateThread', "Terminate Thread"), CONTEXT_IN_DEBUG_MODE); -registerDebugCommandPaletteItem(STEP_OVER_ID, stepOverLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugCommandPaletteItem(STEP_INTO_ID, stepIntoLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugCommandPaletteItem(STEP_OUT_ID, stepOutLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugCommandPaletteItem(PAUSE_ID, pauseLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('running')); -registerDebugCommandPaletteItem(DISCONNECT_ID, disconnectLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_FOCUSED_SESSION_IS_ATTACH); -registerDebugCommandPaletteItem(STOP_ID, stopLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated()); -registerDebugCommandPaletteItem(CONTINUE_ID, continueLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCommandPaletteItem(STEP_OVER_ID, STEP_OVER_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCommandPaletteItem(STEP_INTO_ID, STEP_INTO_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCommandPaletteItem(STEP_OUT_ID, STEP_OUT_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCommandPaletteItem(PAUSE_ID, PAUSE_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('running')); +registerDebugCommandPaletteItem(DISCONNECT_ID, DISCONNECT_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_FOCUSED_SESSION_IS_ATTACH); +registerDebugCommandPaletteItem(STOP_ID, STOP_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated()); +registerDebugCommandPaletteItem(CONTINUE_ID, CONTINUE_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); registerDebugCommandPaletteItem(FOCUS_REPL_ID, nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugFocusConsole' }, 'Focus on Debug Console View')); registerDebugCommandPaletteItem(JUMP_TO_CURSOR_ID, nls.localize('jumpToCursor', "Jump to Cursor"), ContextKeyExpr.and(CONTEXT_JUMP_TO_CURSOR_SUPPORTED)); registerDebugCommandPaletteItem(RunToCursorAction.ID, RunToCursorAction.LABEL, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'))); @@ -265,6 +259,11 @@ configurationRegistry.registerConfiguration({ type: 'boolean', description: nls.localize('debug.focusWindowOnBreak', "Controls whether the workbench window should be focused when the debugger breaks."), default: true + }, + 'debug.onTaskErrors': { + enum: ['debugAnyway', 'showErrors', 'prompt'], + description: nls.localize('debug.onTaskErrors', "Controls what to do when errors are encountered after running a preLaunchTask."), + default: 'prompt' } } }); @@ -274,7 +273,7 @@ Registry.as(WorkbenchExtensions.Workbench).regi // Debug toolbar -const registerDebugToolBarItem = (id: string, title: string, icon: string, order: number, when?: ContextKeyExpr, precondition?: ContextKeyExpr) => { +const registerDebugToolBarItem = (id: string, title: string, iconLightUri: URI, iconDarkUri: URI, order: number, when?: ContextKeyExpr, precondition?: ContextKeyExpr) => { MenuRegistry.appendMenuItem(MenuId.DebugToolBar, { group: 'navigation', when, @@ -283,24 +282,24 @@ const registerDebugToolBarItem = (id: string, title: string, icon: string, order id, title, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/debug/browser/media/${icon}-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/debug/browser/media/${icon}-dark.svg`)) + light: iconLightUri, + dark: iconDarkUri }, precondition } }); }; -registerDebugToolBarItem(CONTINUE_ID, continueLabel, 'continue', 10, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(PAUSE_ID, pauseLabel, 'pause', 10, CONTEXT_DEBUG_STATE.notEqualsTo('stopped')); -registerDebugToolBarItem(STOP_ID, stopLabel, 'stop', 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated()); -registerDebugToolBarItem(DISCONNECT_ID, disconnectLabel, 'disconnect', 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH); -registerDebugToolBarItem(STEP_OVER_ID, stepOverLabel, 'step-over', 20, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(STEP_INTO_ID, stepIntoLabel, 'step-into', 30, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(STEP_OUT_ID, stepOutLabel, 'step-out', 40, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(RESTART_SESSION_ID, restartLabel, 'restart', 60); -registerDebugToolBarItem(STEP_BACK_ID, nls.localize('stepBackDebug', "Step Back"), 'step-back', 50, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(REVERSE_CONTINUE_ID, nls.localize('reverseContinue', "Reverse"), 'reverse-continue', 60, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(CONTINUE_ID, CONTINUE_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-dark.svg')), 10, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(PAUSE_ID, PAUSE_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/pause-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/pause-dark.svg')), 10, CONTEXT_DEBUG_STATE.notEqualsTo('stopped')); +registerDebugToolBarItem(STOP_ID, STOP_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stop-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stop-dark.svg')), 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated()); +registerDebugToolBarItem(DISCONNECT_ID, DISCONNECT_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/disconnect-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/disconnect-dark.svg')), 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH); +registerDebugToolBarItem(STEP_OVER_ID, STEP_OVER_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-over-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-over-dark.svg')), 20, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(STEP_INTO_ID, STEP_INTO_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-into-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-into-dark.svg')), 30, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(STEP_OUT_ID, STEP_OUT_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-out-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-out-dark.svg')), 40, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(RESTART_SESSION_ID, RESTART_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/restart-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/restart-dark.svg')), 60); +registerDebugToolBarItem(STEP_BACK_ID, nls.localize('stepBackDebug', "Step Back"), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-back-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-back-dark.svg')), 50, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(REVERSE_CONTINUE_ID, nls.localize('reverseContinue', "Reverse"), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/reverse-continue-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/reverse-continue-dark.svg')), 60, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); // Debug callstack context menu const registerDebugCallstackItem = (id: string, title: string, order: number, when?: ContextKeyExpr, precondition?: ContextKeyExpr, group = 'navigation') => { @@ -315,13 +314,13 @@ const registerDebugCallstackItem = (id: string, title: string, order: number, wh } }); }; -registerDebugCallstackItem(RESTART_SESSION_ID, restartLabel, 10, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('session')); -registerDebugCallstackItem(STOP_ID, stopLabel, 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('session')); -registerDebugCallstackItem(PAUSE_ID, pauseLabel, 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('running'))); -registerDebugCallstackItem(CONTINUE_ID, continueLabel, 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped'))); -registerDebugCallstackItem(STEP_OVER_ID, stepOverLabel, 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugCallstackItem(STEP_INTO_ID, stepIntoLabel, 30, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugCallstackItem(STEP_OUT_ID, stepOutLabel, 40, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCallstackItem(RESTART_SESSION_ID, RESTART_LABEL, 10, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('session')); +registerDebugCallstackItem(STOP_ID, STOP_LABEL, 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('session')); +registerDebugCallstackItem(PAUSE_ID, PAUSE_LABEL, 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('running'))); +registerDebugCallstackItem(CONTINUE_ID, CONTINUE_LABEL, 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped'))); +registerDebugCallstackItem(STEP_OVER_ID, STEP_OVER_LABEL, 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCallstackItem(STEP_INTO_ID, STEP_INTO_LABEL, 30, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCallstackItem(STEP_OUT_ID, STEP_OUT_LABEL, 40, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); registerDebugCallstackItem(TERMINATE_THREAD_ID, nls.localize('terminateThread', "Terminate Thread"), 10, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), undefined, 'termination'); registerDebugCallstackItem(RESTART_FRAME_ID, nls.localize('restartFrame', "Restart Frame"), 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('stackFrame'), CONTEXT_RESTART_FRAME_SUPPORTED)); registerDebugCallstackItem(COPY_STACK_TRACE_ID, nls.localize('copyStackTrace', "Copy Call Stack"), 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('stackFrame')); @@ -544,12 +543,12 @@ MenuRegistry.appendMenuItem(MenuId.MenubarDebugMenu, { // Touch Bar if (isMacintosh) { - const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr | undefined, icon: string) => { + const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr | undefined, iconUri: URI) => { MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { command: { id, title, - iconLocation: { dark: URI.parse(require.toUrl(`vs/workbench/contrib/debug/browser/media/${icon}`)) } + iconLocation: { dark: iconUri } }, when, group: '9_debug', @@ -557,13 +556,13 @@ if (isMacintosh) { }); }; - registerTouchBarEntry(StartAction.ID, StartAction.LABEL, 0, CONTEXT_IN_DEBUG_MODE.toNegated(), 'continue-tb.png'); - registerTouchBarEntry(RunAction.ID, RunAction.LABEL, 1, CONTEXT_IN_DEBUG_MODE.toNegated(), 'continue-without-debugging-tb.png'); - registerTouchBarEntry(CONTINUE_ID, continueLabel, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'continue-tb.png'); - registerTouchBarEntry(PAUSE_ID, pauseLabel, 1, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.notEquals('debugState', 'stopped')), 'pause-tb.png'); - registerTouchBarEntry(STEP_OVER_ID, stepOverLabel, 2, CONTEXT_IN_DEBUG_MODE, 'stepover-tb.png'); - registerTouchBarEntry(STEP_INTO_ID, stepIntoLabel, 3, CONTEXT_IN_DEBUG_MODE, 'stepinto-tb.png'); - registerTouchBarEntry(STEP_OUT_ID, stepOutLabel, 4, CONTEXT_IN_DEBUG_MODE, 'stepout-tb.png'); - registerTouchBarEntry(RESTART_SESSION_ID, restartLabel, 5, CONTEXT_IN_DEBUG_MODE, 'restart-tb.png'); - registerTouchBarEntry(STOP_ID, stopLabel, 6, CONTEXT_IN_DEBUG_MODE, 'stop-tb.png'); + registerTouchBarEntry(StartAction.ID, StartAction.LABEL, 0, CONTEXT_IN_DEBUG_MODE.toNegated(), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-tb.png'))); + registerTouchBarEntry(RunAction.ID, RunAction.LABEL, 1, CONTEXT_IN_DEBUG_MODE.toNegated(), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-without-debugging-tb.png'))); + registerTouchBarEntry(CONTINUE_ID, CONTINUE_LABEL, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-tb.png'))); + registerTouchBarEntry(PAUSE_ID, PAUSE_LABEL, 1, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.notEquals('debugState', 'stopped')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/pause-tb.png'))); + registerTouchBarEntry(STEP_OVER_ID, STEP_OVER_LABEL, 2, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stepover-tb.png'))); + registerTouchBarEntry(STEP_INTO_ID, STEP_INTO_LABEL, 3, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stepinto-tb.png'))); + registerTouchBarEntry(STEP_OUT_ID, STEP_OUT_LABEL, 4, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stepout-tb.png'))); + registerTouchBarEntry(RESTART_SESSION_ID, RESTART_LABEL, 5, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/restart-tb.png'))); + registerTouchBarEntry(STOP_ID, STOP_LABEL, 6, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stop-tb.png'))); } diff --git a/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts b/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts index 9290abdbe2..0d1752cade 100644 --- a/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts +++ b/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts @@ -209,7 +209,13 @@ export class FocusSessionActionViewItem extends SelectActionViewItem { } })); - this._register(this.debugService.onDidNewSession(() => this.update())); + this._register(this.debugService.onDidNewSession(session => { + this._register(session.onDidChangeName(() => this.update())); + this.update(); + })); + this.getSessions().forEach(session => { + this._register(session.onDidChangeName(() => this.update())); + }); this._register(this.debugService.onDidEndSession(() => this.update())); this.update(); diff --git a/src/vs/workbench/contrib/debug/browser/debugActions.ts b/src/vs/workbench/contrib/debug/browser/debugActions.ts index 308b45f8c5..f9ed48bf59 100644 --- a/src/vs/workbench/contrib/debug/browser/debugActions.ts +++ b/src/vs/workbench/contrib/debug/browser/debugActions.ts @@ -210,7 +210,7 @@ export class RemoveAllBreakpointsAction extends AbstractDebugAction { protected isEnabled(state: State): boolean { const model = this.debugService.getModel(); - return super.isEnabled(state) && (model.getBreakpoints().length > 0 || model.getFunctionBreakpoints().length > 0); + return super.isEnabled(state) && (model.getBreakpoints().length > 0 || model.getFunctionBreakpoints().length > 0 || model.getDataBreakpoints().length > 0); } } @@ -272,7 +272,7 @@ export class ToggleBreakpointsActivatedAction extends AbstractDebugAction { } protected isEnabled(state: State): boolean { - return (this.debugService.getModel().getFunctionBreakpoints().length + this.debugService.getModel().getBreakpoints().length) > 0; + return !!(this.debugService.getModel().getFunctionBreakpoints().length || this.debugService.getModel().getBreakpoints().length || this.debugService.getModel().getDataBreakpoints().length); } } @@ -292,7 +292,7 @@ export class ReapplyBreakpointsAction extends AbstractDebugAction { protected isEnabled(state: State): boolean { const model = this.debugService.getModel(); return super.isEnabled(state) && (state === State.Running || state === State.Stopped) && - (model.getFunctionBreakpoints().length + model.getBreakpoints().length + model.getExceptionBreakpoints().length > 0); + ((model.getFunctionBreakpoints().length + model.getBreakpoints().length + model.getExceptionBreakpoints().length + model.getDataBreakpoints().length) > 0); } } diff --git a/src/vs/workbench/contrib/debug/browser/debugCommands.ts b/src/vs/workbench/contrib/debug/browser/debugCommands.ts index 06fb7f05ed..e4f2f461bd 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCommands.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCommands.ts @@ -51,6 +51,15 @@ export const CONTINUE_ID = 'workbench.action.debug.continue'; export const FOCUS_REPL_ID = 'workbench.debug.action.focusRepl'; export const JUMP_TO_CURSOR_ID = 'debug.jumpToCursor'; +export const RESTART_LABEL = nls.localize('restartDebug', "Restart"); +export const STEP_OVER_LABEL = nls.localize('stepOverDebug', "Step Over"); +export const STEP_INTO_LABEL = nls.localize('stepIntoDebug', "Step Into"); +export const STEP_OUT_LABEL = nls.localize('stepOutDebug', "Step Out"); +export const PAUSE_LABEL = nls.localize('pauseDebug', "Pause"); +export const DISCONNECT_LABEL = nls.localize('disconnect', "Disconnect"); +export const STOP_LABEL = nls.localize('stop', "Stop"); +export const CONTINUE_LABEL = nls.localize('continueDebug', "Continue"); + function getThreadAndRun(accessor: ServicesAccessor, thread: IThread | undefined, run: (thread: IThread) => Promise, ): void { const debugService = accessor.get(IDebugService); if (!(thread instanceof Thread)) { @@ -224,9 +233,9 @@ export function registerCommands(): void { CommandsRegistry.registerCommand({ id: DISCONNECT_ID, - handler: (accessor: ServicesAccessor) => { + handler: (accessor: ServicesAccessor, _: string, session: IDebugSession | undefined) => { const debugService = accessor.get(IDebugService); - const session = debugService.getViewModel().focusedSession; + session = session || debugService.getViewModel().focusedSession; debugService.stopSession(session).then(undefined, onUnexpectedError); } }); diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index b0d2c17684..d2148dc75d 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -41,7 +41,7 @@ import { ContextSubMenu } from 'vs/base/browser/contextmenu'; import { memoize } from 'vs/base/common/decorators'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { getHover } from 'vs/editor/contrib/hover/getHover'; -import { IEditorHoverOptions } from 'vs/editor/common/config/editorOptions'; +import { IEditorHoverOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { CancellationToken } from 'vs/base/common/cancellation'; import { BreakpointWidget } from 'vs/workbench/contrib/debug/browser/breakpointWidget'; import { DebugHoverWidget } from 'vs/workbench/contrib/debug/browser/debugHover'; @@ -168,7 +168,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { } private registerListeners(): void { - this.toDispose.push(this.editor.onMouseDown((e: IEditorMouseEvent) => { + this.toDispose.push(this.editor.onMouseDown(async (e: IEditorMouseEvent) => { const data = e.target.detail as IMarginData; const model = this.editor.getModel(); if (!e.target.position || !model || e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN || data.isAfterLines || !this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) { @@ -213,18 +213,18 @@ export class DebugEditorContribution implements IDebugEditorContribution { logPoint ? nls.localize('message', "message") : nls.localize('condition', "condition") ); - this.dialogService.show(severity.Info, disable ? disabling : enabling, [ + const { choice } = await this.dialogService.show(severity.Info, disable ? disabling : enabling, [ nls.localize('removeLogPoint', "Remove {0}", breakpointType), nls.localize('disableLogPoint', "{0} {1}", disable ? nls.localize('disable', "Disable") : nls.localize('enable', "Enable"), breakpointType), nls.localize('cancel', "Cancel") - ], { cancelId: 2 }).then(choice => { - if (choice === 0) { - breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId())); - } - if (choice === 1) { - breakpoints.forEach(bp => this.debugService.enableOrDisableBreakpoints(!disable, bp)); - } - }); + ], { cancelId: 2 }); + + if (choice === 0) { + breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId())); + } + if (choice === 1) { + breakpoints.forEach(bp => this.debugService.enableOrDisableBreakpoints(!disable, bp)); + } } else { breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId())); } @@ -540,7 +540,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { if (this.configurationWidget) { this.configurationWidget.dispose(); } - if (model && LAUNCH_JSON_REGEX.test(model.uri.toString()) && !this.editor.getConfiguration().readOnly) { + if (model && LAUNCH_JSON_REGEX.test(model.uri.toString()) && !this.editor.getOption(EditorOption.readOnly)) { this.configurationWidget = this.instantiationService.createInstance(FloatingClickWidget, this.editor, nls.localize('addConfiguration', "Add Configuration..."), null); this.configurationWidget.render(); this.toDispose.push(this.configurationWidget.onClick(() => this.addLaunchConfiguration())); diff --git a/src/vs/workbench/contrib/debug/browser/debugHover.ts b/src/vs/workbench/contrib/debug/browser/debugHover.ts index ba896e2c0c..5492749b70 100644 --- a/src/vs/workbench/contrib/debug/browser/debugHover.ts +++ b/src/vs/workbench/contrib/debug/browser/debugHover.ts @@ -9,7 +9,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import * as dom from 'vs/base/browser/dom'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { IContentWidget, ICodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; @@ -73,13 +73,13 @@ export class DebugHoverWidget implements IContentWidget { this.treeContainer.setAttribute('role', 'tree'); const dataSource = new DebugHoverDataSource(); - this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, this.treeContainer, new DebugHoverDelegate(), [this.instantiationService.createInstance(VariablesRenderer)], + this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'DebugHover', this.treeContainer, new DebugHoverDelegate(), [this.instantiationService.createInstance(VariablesRenderer)], dataSource, { - ariaLabel: nls.localize('treeAriaLabel', "Debug Hover"), - accessibilityProvider: new DebugHoverAccessibilityProvider(), - mouseSupport: false, - horizontalScrolling: true - }); + ariaLabel: nls.localize('treeAriaLabel', "Debug Hover"), + accessibilityProvider: new DebugHoverAccessibilityProvider(), + mouseSupport: false, + horizontalScrolling: true + }); this.valueContainer = $('.value'); this.valueContainer.tabIndex = 0; @@ -114,8 +114,8 @@ export class DebugHoverWidget implements IContentWidget { this.hide(); } })); - this.toDispose.push(this.editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - if (e.fontInfo) { + this.toDispose.push(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.fontInfo)) { this.editor.applyFontInfo(this.domNode); } })); diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index f999a02033..ddc7f44415 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -37,7 +37,7 @@ import { parse, getFirstFrame } from 'vs/base/common/console'; import { TaskEvent, TaskEventKind, TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { IAction, Action } from 'vs/base/common/actions'; +import { IAction } from 'vs/base/common/actions'; import { deepClone, equals } from 'vs/base/common/objects'; import { DebugSession } from 'vs/workbench/contrib/debug/browser/debugSession'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; @@ -50,7 +50,6 @@ import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint'; -const DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated'; const DEBUG_FUNCTION_BREAKPOINTS_KEY = 'debug.functionbreakpoint'; const DEBUG_DATA_BREAKPOINTS_KEY = 'debug.databreakpoint'; const DEBUG_EXCEPTION_BREAKPOINTS_KEY = 'debug.exceptionbreakpoint'; @@ -74,7 +73,7 @@ const enum TaskRunResult { } export class DebugService implements IDebugService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _onDidChangeState: Emitter; private readonly _onDidNewSession: Emitter; @@ -129,7 +128,7 @@ export class DebugService implements IDebugService { this.debugState = CONTEXT_DEBUG_STATE.bindTo(contextKeyService); this.inDebugMode = CONTEXT_IN_DEBUG_MODE.bindTo(contextKeyService); - this.model = new DebugModel(this.loadBreakpoints(), this.storageService.getBoolean(DEBUG_BREAKPOINTS_ACTIVATED_KEY, StorageScope.WORKSPACE, true), this.loadFunctionBreakpoints(), + this.model = new DebugModel(this.loadBreakpoints(), this.loadFunctionBreakpoints(), this.loadExceptionBreakpoints(), this.loadDataBreakpoints(), this.loadWatchExpressions(), this.textFileService); this.toDispose.push(this.model); @@ -671,29 +670,33 @@ export class DebugService implements IDebugService { return Promise.resolve(config); } - private showError(message: string, errorActions: ReadonlyArray = []): Promise { + private async showError(message: string, errorActions: ReadonlyArray = []): Promise { const configureAction = this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL); const actions = [...errorActions, configureAction]; - return this.dialogService.show(severity.Error, message, actions.map(a => a.label).concat(nls.localize('cancel', "Cancel")), { cancelId: actions.length }).then(choice => { - if (choice < actions.length) { - return actions[choice].run(); - } + const { choice } = await this.dialogService.show(severity.Error, message, actions.map(a => a.label).concat(nls.localize('cancel', "Cancel")), { cancelId: actions.length }); + if (choice < actions.length) { + return actions[choice].run(); + } - return undefined; - }); + return undefined; } //---- task management private runTaskAndCheckErrors(root: IWorkspaceFolder | undefined, taskId: string | TaskIdentifier | undefined): Promise { - const debugAnywayAction = new Action('debug.debugAnyway', nls.localize('debugAnyway', "Debug Anyway"), undefined, true, () => Promise.resolve(TaskRunResult.Success)); return this.runTask(root, taskId).then((taskSummary: ITaskSummary) => { + const errorCount = taskId ? this.markerService.getStatistics().errors : 0; const successExitCode = taskSummary && taskSummary.exitCode === 0; const failureExitCode = taskSummary && taskSummary.exitCode !== undefined && taskSummary.exitCode !== 0; - if (successExitCode || (errorCount === 0 && !failureExitCode)) { - return TaskRunResult.Success; + const onTaskErrors = this.configurationService.getValue('debug').onTaskErrors; + if (successExitCode || onTaskErrors === 'debugAnyway' || (errorCount === 0 && !failureExitCode)) { + return TaskRunResult.Success; + } + if (onTaskErrors === 'showErrors') { + this.panelService.openPanel(Constants.MARKERS_PANEL_ID); + return Promise.resolve(TaskRunResult.Failure); } const taskLabel = typeof taskId === 'string' ? taskId : taskId ? taskId.name : ''; @@ -703,14 +706,28 @@ export class DebugService implements IDebugService { ? nls.localize('preLaunchTaskError', "Error exists after running preLaunchTask '{0}'.", taskLabel) : nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", taskLabel, taskSummary.exitCode); - const showErrorsAction = new Action('debug.showErrors', nls.localize('showErrors', "Show Errors"), undefined, true, () => { + return this.dialogService.show(severity.Warning, message, [nls.localize('debugAnyway', "Debug Anyway"), nls.localize('showErrors', "Show Errors"), nls.localize('cancel', "Cancel")], { + checkbox: { + label: nls.localize('remember', "Remember my choice in user settings"), + }, + cancelId: 2 + }).then(result => { + if (result.choice === 2) { + return Promise.resolve(TaskRunResult.Failure); + } + const debugAnyway = result.choice === 0; + if (result.checkboxChecked) { + this.configurationService.updateValue('debug.onTaskErrors', debugAnyway ? 'debugAnyway' : 'showErrors'); + } + if (debugAnyway) { + return TaskRunResult.Success; + } + this.panelService.openPanel(Constants.MARKERS_PANEL_ID); return Promise.resolve(TaskRunResult.Failure); }); - - return this.showError(message, [debugAnywayAction, showErrorsAction]); }, (err: TaskError) => { - return this.showError(err.message, [debugAnywayAction, this.taskService.configureAction()]); + return this.showError(err.message, [this.taskService.configureAction()]); }); } @@ -901,12 +918,6 @@ export class DebugService implements IDebugService { setBreakpointsActivated(activated: boolean): Promise { this.model.setBreakpointsActivated(activated); - if (activated) { - this.storageService.store(DEBUG_BREAKPOINTS_ACTIVATED_KEY, 'false', StorageScope.WORKSPACE); - } else { - this.storageService.remove(DEBUG_BREAKPOINTS_ACTIVATED_KEY, StorageScope.WORKSPACE); - } - return this.sendAllBreakpoints(); } @@ -944,7 +955,8 @@ export class DebugService implements IDebugService { return Promise.all(distinct(this.model.getBreakpoints(), bp => bp.uri.toString()).map(bp => this.sendBreakpoints(bp.uri, false, session))) .then(() => this.sendFunctionBreakpoints(session)) // send exception breakpoints at the end since some debug adapters rely on the order - .then(() => this.sendExceptionBreakpoints(session)); + .then(() => this.sendExceptionBreakpoints(session)) + .then(() => this.sendDataBreakpoints(session)); } private sendBreakpoints(modelUri: uri, sourceModified = false, session?: IDebugSession): Promise { diff --git a/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index 791801615e..41bcd6b563 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -33,6 +33,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { variableSetEmitter } from 'vs/workbench/contrib/debug/browser/variablesView'; +import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation'; export class DebugSession implements IDebugSession { @@ -43,6 +44,7 @@ export class DebugSession implements IDebugSession { private sources = new Map(); private threads = new Map(); + private cancellationMap = new Map(); private rawListeners: IDisposable[] = []; private fetchThreadsScheduler: RunOnceScheduler | undefined; private repl: ReplModel; @@ -55,6 +57,9 @@ export class DebugSession implements IDebugSession { private readonly _onDidChangeREPLElements = new Emitter(); + private name: string | undefined; + private readonly _onDidChangeName = new Emitter(); + constructor( private _configuration: { resolved: IConfig, unresolved: IConfig | undefined }, public root: IWorkspaceFolder, @@ -105,7 +110,13 @@ export class DebugSession implements IDebugSession { getLabel(): string { const includeRoot = this.workspaceContextService.getWorkspace().folders.length > 1; - return includeRoot && this.root ? `${this.configuration.name} (${resources.basenameOrAuthority(this.root.uri)})` : this.configuration.name; + const name = this.name || this.configuration.name; + return includeRoot && this.root ? `${name} (${resources.basenameOrAuthority(this.root.uri)})` : name; + } + + setName(name: string): void { + this.name = name; + this._onDidChangeName.fire(name); } get state(): State { @@ -144,6 +155,10 @@ export class DebugSession implements IDebugSession { return this._onDidChangeREPLElements.event; } + get onDidChangeName(): Event { + return this._onDidChangeName.event; + } + //---- DAP events get onDidCustomEvent(): Event { @@ -222,6 +237,7 @@ export class DebugSession implements IDebugSession { */ terminate(restart = false): Promise { if (this.raw) { + this.cancelAllRequests(); if (this.raw.capabilities.supportsTerminateRequest && this._configuration.resolved.request === 'launch') { return this.raw.terminate(restart).then(response => { return undefined; @@ -239,6 +255,7 @@ export class DebugSession implements IDebugSession { */ disconnect(restart = false): Promise { if (this.raw) { + this.cancelAllRequests(); return this.raw.disconnect(restart).then(response => { return undefined; }); @@ -251,6 +268,7 @@ export class DebugSession implements IDebugSession { */ restart(): Promise { if (this.raw) { + this.cancelAllRequests(); return this.raw.restart().then(() => undefined); } return Promise.reject(new Error('no debug adapter')); @@ -367,7 +385,8 @@ export class DebugSession implements IDebugSession { stackTrace(threadId: number, startFrame: number, levels: number): Promise { if (this.raw) { - return this.raw.stackTrace({ threadId, startFrame, levels }); + const token = this.getNewCancellationToken(threadId); + return this.raw.stackTrace({ threadId, startFrame, levels }, token); } return Promise.reject(new Error('no debug adapter')); } @@ -389,16 +408,18 @@ export class DebugSession implements IDebugSession { return Promise.reject(new Error('no debug adapter')); } - scopes(frameId: number): Promise { + scopes(frameId: number, threadId: number): Promise { if (this.raw) { - return this.raw.scopes({ frameId }); + const token = this.getNewCancellationToken(threadId); + return this.raw.scopes({ frameId }, token); } return Promise.reject(new Error('no debug adapter')); } - variables(variablesReference: number, filter: 'indexed' | 'named' | undefined, start: number | undefined, count: number | undefined): Promise { + variables(variablesReference: number, threadId: number | undefined, filter: 'indexed' | 'named' | undefined, start: number | undefined, count: number | undefined): Promise { if (this.raw) { - return this.raw.variables({ variablesReference, filter, start, count }); + const token = threadId ? this.getNewCancellationToken(threadId) : undefined; + return this.raw.variables({ variablesReference, filter, start, count }, token); } return Promise.reject(new Error('no debug adapter')); } @@ -506,17 +527,8 @@ export class DebugSession implements IDebugSession { rawSource = source.raw; } else { // create a Source - - let sourceRef: number | undefined; - if (resource.query) { - const data = Source.getEncodedDebugData(resource); - sourceRef = data.sourceReference; - } - - rawSource = { - path: resource.with({ scheme: '', query: '' }).toString(true), // Remove debug: scheme - sourceReference: sourceRef - }; + const data = Source.getEncodedDebugData(resource); + rawSource = { path: data.path, sourceReference: data.sourceReference }; } return this.raw.source({ sourceReference: rawSource.sourceReference || 0, source: rawSource }); @@ -537,14 +549,14 @@ export class DebugSession implements IDebugSession { return Promise.reject(new Error('no debug adapter')); } - completions(frameId: number | undefined, text: string, position: Position, overwriteBefore: number): Promise { + completions(frameId: number | undefined, text: string, position: Position, overwriteBefore: number, token: CancellationToken): Promise { if (this.raw) { return this.raw.completions({ frameId, text, column: position.column, - line: position.lineNumber - }).then(response => { + line: position.lineNumber, + }, token).then(response => { const result: CompletionItem[] = []; if (response && response.body && response.body.targets) { @@ -753,6 +765,16 @@ export class DebugSession implements IDebugSession { this.rawListeners.push(this.raw.onDidContinued(event => { const threadId = event.body.allThreadsContinued !== false ? undefined : event.body.threadId; + if (threadId) { + const tokens = this.cancellationMap.get(threadId); + this.cancellationMap.delete(threadId); + if (tokens) { + tokens.forEach(t => t.cancel()); + } + } else { + this.cancelAllRequests(); + } + this.model.clearThreads(this.getId(), false, threadId); this._onDidChangeState.fire(); })); @@ -783,7 +805,7 @@ export class DebugSession implements IDebugSession { source: this.getSource(event.body.source) } : undefined; if (event.body.variablesReference) { - const container = new ExpressionContainer(this, event.body.variablesReference, generateUuid()); + const container = new ExpressionContainer(this, undefined, event.body.variablesReference, generateUuid()); outpuPromises.push(container.getChildren().then(children => { return Promise.all(waitFor).then(() => children.forEach(child => { // Since we can not display multiple trees in a row, we are displaying these variables one after the other (ignoring their names) @@ -799,8 +821,8 @@ export class DebugSession implements IDebugSession { this.rawListeners.push(this.raw.onDidBreakpoint(event => { const id = event.body && event.body.breakpoint ? event.body.breakpoint.id : undefined; - const breakpoint = this.model.getBreakpoints().filter(bp => bp.idFromAdapter === id).pop(); - const functionBreakpoint = this.model.getFunctionBreakpoints().filter(bp => bp.idFromAdapter === id).pop(); + const breakpoint = this.model.getBreakpoints().filter(bp => bp.getIdFromAdapter(this.getId()) === id).pop(); + const functionBreakpoint = this.model.getFunctionBreakpoints().filter(bp => bp.getIdFromAdapter(this.getId()) === id).pop(); if (event.body.reason === 'new' && event.body.breakpoint.source && event.body.breakpoint.line) { const source = this.getSource(event.body.breakpoint.source); @@ -860,6 +882,7 @@ export class DebugSession implements IDebugSession { dispose(this.rawListeners); if (this.raw) { this.raw.disconnect(); + this.raw.dispose(); } this.raw = undefined; this.model.clearThreads(this.getId(), true); @@ -891,6 +914,20 @@ export class DebugSession implements IDebugSession { return source; } + private getNewCancellationToken(threadId: number): CancellationToken { + const tokenSource = new CancellationTokenSource(); + const tokens = this.cancellationMap.get(threadId) || []; + tokens.push(tokenSource); + this.cancellationMap.set(threadId, tokens); + + return tokenSource.token; + } + + private cancelAllRequests(): void { + this.cancellationMap.forEach(tokens => tokens.forEach(t => t.cancel())); + this.cancellationMap.clear(); + } + private getUriKey(uri: URI): string { // TODO: the following code does not make sense if uri originates from a different platform return platform.isLinux ? uri.toString() : uri.toString().toLowerCase(); @@ -908,11 +945,11 @@ export class DebugSession implements IDebugSession { } async addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise { - const viewModel = this.debugService.getViewModel(); - await this.repl.addReplExpression(stackFrame, name); + const expressionEvaluated = this.repl.addReplExpression(stackFrame, name); + this._onDidChangeREPLElements.fire(); + await expressionEvaluated; this._onDidChangeREPLElements.fire(); // Evaluate all watch expressions and fetch variables again since repl evaluation might have changed some. - this.debugService.focusStackFrame(viewModel.focusedStackFrame, viewModel.focusedThread, viewModel.focusedSession); variableSetEmitter.fire(); } diff --git a/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts index f7da5631d4..1d2a3e20fa 100644 --- a/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts +++ b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts @@ -15,6 +15,7 @@ import { Color } from 'vs/base/common/color'; import { registerColor } from 'vs/platform/theme/common/colorRegistry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const $ = dom.$; // theming @@ -62,7 +63,7 @@ export class ExceptionWidget extends ZoneWidget { protected _fillContainer(container: HTMLElement): void { this.setCssClass('exception-widget'); // Set the font size and line height to the one from the editor configuration. - const fontInfo = this.editor.getConfiguration().fontInfo; + const fontInfo = this.editor.getOption(EditorOption.fontInfo); container.style.fontSize = `${fontInfo.fontSize}px`; container.style.lineHeight = `${fontInfo.lineHeight}px`; @@ -89,7 +90,7 @@ export class ExceptionWidget extends ZoneWidget { // Reload the height with respect to the exception text content and relayout it to match the line count. this.container!.style.height = 'initial'; - const lineHeight = this.editor.getConfiguration().lineHeight; + const lineHeight = this.editor.getOption(EditorOption.lineHeight); const arrowHeight = Math.round(lineHeight / 3); const computedLinesNumber = Math.ceil((this.container!.offsetHeight + arrowHeight) / lineHeight); diff --git a/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts index edc3aea0c2..4f604bdfe4 100644 --- a/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts +++ b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts @@ -9,9 +9,10 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; import { IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; +import { IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { Event } from 'vs/base/common/event'; class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient { @@ -22,11 +23,16 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient { ) { const connection = remoteAgentService.getConnection(); - if (!connection) { - throw new Error('Missing agent connection'); + let channel: IChannel; + if (connection) { + channel = connection.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName); + } else { + channel = { call: async () => undefined, listen: () => Event.None } as any; + // TODO@weinand TODO@isidorn fallback? + console.warn('Extension Host Debugging not available due to missing connection.'); } - super(connection.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName)); + super(channel); this._register(this.onReload(event => { if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) { @@ -45,7 +51,7 @@ registerSingleton(IExtensionHostDebugService, BrowserExtensionHostDebugService); class BrowserDebugHelperService implements IDebugHelperService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; createTelemetryService(configurationService: IConfigurationService, args: string[]): TelemetryService | undefined { return undefined; diff --git a/src/vs/workbench/contrib/debug/browser/linkDetector.ts b/src/vs/workbench/contrib/debug/browser/linkDetector.ts index ed2eaaa179..ddd4b2d274 100644 --- a/src/vs/workbench/contrib/debug/browser/linkDetector.ts +++ b/src/vs/workbench/contrib/debug/browser/linkDetector.ts @@ -9,7 +9,7 @@ import { URI as uri } from 'vs/base/common/uri'; import { isMacintosh } from 'vs/base/common/platform'; import { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import * as nls from 'vs/nls'; -import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; export class LinkDetector { private static readonly MAX_LENGTH = 500; @@ -87,11 +87,13 @@ export class LinkDetector { const link = document.createElement('a'); link.textContent = line.substr(match.index, match[0].length); - link.title = isMacintosh ? nls.localize('fileLinkMac', "Click to follow (Cmd + click opens to the side)") : nls.localize('fileLink', "Click to follow (Ctrl + click opens to the side)"); + link.title = isMacintosh ? nls.localize('fileLinkMac', "Cmd + click to follow link") : nls.localize('fileLink', "Ctrl + click to follow link"); lineContainer.appendChild(link); const lineNumber = Number(match[3]); const columnNumber = match[4] ? Number(match[4]) : undefined; link.onclick = (e) => this.onLinkClick(new StandardMouseEvent(e), resource!, lineNumber, columnNumber); + link.onmousemove = (event) => link.classList.toggle('pointer', isMacintosh ? event.metaKey : event.ctrlKey); + link.onmouseleave = () => link.classList.remove('pointer'); lastMatchIndex = pattern.lastIndex; const currentMatch = match; @@ -141,9 +143,11 @@ export class LinkDetector { if (!selection || selection.type === 'Range') { return; // do not navigate when user is selecting } + if (!(isMacintosh ? event.metaKey : event.ctrlKey)) { + return; + } event.preventDefault(); - const group = event.ctrlKey || event.metaKey ? SIDE_GROUP : ACTIVE_GROUP; this.editorService.openEditor({ resource, @@ -153,6 +157,6 @@ export class LinkDetector { startColumn: column } } - }, group); + }); } } diff --git a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts index 96c091d828..85d00120cd 100644 --- a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts +++ b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts @@ -419,7 +419,7 @@ export class LoadedScriptsView extends ViewletPanel { this.treeLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility }); this._register(this.treeLabels); - this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, this.treeContainer, new LoadedScriptsDelegate(), + this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'LoadedScriptsView', this.treeContainer, new LoadedScriptsDelegate(), [new LoadedScriptsRenderer(this.treeLabels)], new LoadedScriptsDataSource(), { @@ -466,7 +466,21 @@ export class LoadedScriptsView extends ViewletPanel { } })); - const registerLoadedSourceListener = (session: IDebugSession) => { + const scheduleRefreshOnVisible = () => { + if (this.isBodyVisible()) { + this.changeScheduler.schedule(); + } else { + this.treeNeedsRefreshOnVisible = true; + } + }; + + const registerSessionListeners = (session: IDebugSession) => { + this._register(session.onDidChangeName(() => { + // Re-add session, this will trigger proper sorting and id recalculation. + root.remove(session.getId()); + root.add(session); + scheduleRefreshOnVisible(); + })); this._register(session.onDidLoadedSource(event => { let sessionRoot: SessionTreeItem; switch (event.reason) { @@ -474,11 +488,7 @@ export class LoadedScriptsView extends ViewletPanel { case 'changed': sessionRoot = root.add(session); sessionRoot.addPath(event.source); - if (this.isBodyVisible()) { - this.changeScheduler.schedule(); - } else { - this.treeNeedsRefreshOnVisible = true; - } + scheduleRefreshOnVisible(); if (event.reason === 'changed') { DebugContentProvider.refreshDebugContent(event.source.uri); } @@ -486,11 +496,7 @@ export class LoadedScriptsView extends ViewletPanel { case 'removed': sessionRoot = root.find(session); if (sessionRoot && sessionRoot.removePath(event.source)) { - if (this.isBodyVisible()) { - this.changeScheduler.schedule(); - } else { - this.treeNeedsRefreshOnVisible = true; - } + scheduleRefreshOnVisible(); } break; default: @@ -501,8 +507,8 @@ export class LoadedScriptsView extends ViewletPanel { })); }; - this._register(this.debugService.onDidNewSession(registerLoadedSourceListener)); - this.debugService.getModel().getSessions().forEach(registerLoadedSourceListener); + this._register(this.debugService.onDidNewSession(registerSessionListeners)); + this.debugService.getModel().getSessions().forEach(registerSessionListeners); this._register(this.debugService.onDidEndSession(session => { root.remove(session.getId()); diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional-disabled.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional-disabled.svg deleted file mode 100644 index 75c0a500f4..0000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional-disabled.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional-unverified.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional-unverified.svg deleted file mode 100644 index 85a35a44ff..0000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional-unverified.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-data-disabled.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-data-disabled.svg new file mode 100644 index 0000000000..a2c8c3417e --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/breakpoint-data-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-data-unverified.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-data-unverified.svg new file mode 100644 index 0000000000..96dda92ee3 --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/breakpoint-data-unverified.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-data.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-data.svg new file mode 100644 index 0000000000..6752b060ae --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/breakpoint-data.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/continue-white.svg b/src/vs/workbench/contrib/debug/browser/media/continue-white.svg new file mode 100644 index 0000000000..69d48e9984 --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/continue-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css index 155643353d..c4c5072a29 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css @@ -62,6 +62,18 @@ background: url('breakpoint-function-disabled.svg') center center no-repeat; } +.debug-data-breakpoint { + background: url('breakpoint-data.svg') center center no-repeat; +} + +.debug-data-breakpoint-unverified { + background: url('breakpoint-data-unverified.svg') center center no-repeat; +} + +.debug-data-breakpoint-disabled { + background: url('breakpoint-data-disabled.svg') center center no-repeat; +} + .debug-breakpoint-conditional, .monaco-editor .debug-breakpoint-column.debug-breakpoint-conditional-column::before { background: url('breakpoint-conditional.svg') center center no-repeat; @@ -135,6 +147,16 @@ margin-left: 6px; } +/* Links */ + +.monaco-workbench .monaco-list-row .expression .value a { + text-decoration: underline; +} + +.monaco-workbench .monaco-list-row .expression .value a.pointer { + cursor: pointer; +} + /* White color when element is selected and list is focused. White looks better on blue selection background. */ .monaco-workbench .monaco-list:focus .monaco-list-row.selected .expression .name, .monaco-workbench .monaco-list:focus .monaco-list-row.selected .expression .value { diff --git a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css index 08294e140f..e1bddbd7c5 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css @@ -179,6 +179,27 @@ text-transform: uppercase; } +.debug-viewlet .debug-call-stack .thread:hover > .state, +.debug-viewlet .debug-call-stack .session:hover > .state, +.debug-viewlet .debug-call-stack .monaco-list-row.focused .state { + display: none; +} + +.debug-viewlet .debug-call-stack .monaco-list-row .monaco-action-bar { + display: none; +} + +.debug-viewlet .debug-call-stack .monaco-list-row.focused .monaco-action-bar, +.debug-viewlet .debug-call-stack .monaco-list-row:hover .monaco-action-bar { + display: initial; +} + +.monaco-workbench .debug-viewlet .debug-call-stack .monaco-action-bar .action-item > .action-label { + width: 16px; + height: 100%; + margin-right: 8px; +} + .debug-viewlet .debug-call-stack .thread > .state > .label, .debug-viewlet .debug-call-stack .session > .state > .label { background: rgba(136, 136, 136, 0.3); @@ -257,6 +278,102 @@ overflow: hidden; } +.debug-viewlet .debug-call-stack .debug-action.stop { + background: url('stop-light.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.stop { + background: url('stop-white.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.stop { + background: url('stop-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .debug-action.disconnect { + background: url('disconnect-light.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.disconnect { + background: url('disconnect-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.disconnect { + background: url('disconnect-white.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .debug-action.restart { + background: url('restart-light.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.restart { + background: url('restart-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.restart { + background: url('restart-white.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .debug-action.step-over { + background: url('step-over-light.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.step-over { + background: url('step-over-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.step-over { + background: url('step-over-white.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .debug-action.step-into { + background: url('step-into-light.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.step-into { + background: url('step-into-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.step-into { + background: url('step-into-white.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .debug-action.step-out { + background: url('step-out-light.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.step-out { + background: url('step-out-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.step-out { + background: url('step-out-white.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .debug-action.pause { + background: url('pause-light.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.pause { + background: url('pause-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.pause { + background: url('pause-white.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .debug-action.continue { + background: url('continue-light.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.continue { + background: url('continue-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.continue { + background: url('continue-white.svg') center center no-repeat; +} + /* Variables & Expression view */ .debug-viewlet .scope { diff --git a/src/vs/workbench/contrib/debug/browser/media/disconnect-white.svg b/src/vs/workbench/contrib/debug/browser/media/disconnect-white.svg new file mode 100644 index 0000000000..42e2e75e09 --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/disconnect-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/pause-white.svg b/src/vs/workbench/contrib/debug/browser/media/pause-white.svg new file mode 100644 index 0000000000..bd634a35a5 --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/pause-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/repl.css b/src/vs/workbench/contrib/debug/browser/media/repl.css index b5f28590e7..fae75d5dcc 100644 --- a/src/vs/workbench/contrib/debug/browser/media/repl.css +++ b/src/vs/workbench/contrib/debug/browser/media/repl.css @@ -48,11 +48,13 @@ cursor: text; } -.repl .repl-tree .output.expression > .value { +.repl .repl-tree .output.expression > .value, +.repl .repl-tree .evaluation-result.expression > .value { margin-left: 0px; } -.repl .repl-tree .output.expression > .annotation { +.repl .repl-tree .output.expression > .annotation, +.repl .repl-tree .evaluation-result.expression > .annotation { font-size: inherit; padding-left: 6px; } @@ -67,7 +69,7 @@ } /* Only show 'stale expansion' info when the element gets expanded. */ -.repl .repl-tree .input-output-pair > .output > .annotation::before { +.repl .repl-tree .evaluation-result > .annotation::before { content: ''; } @@ -132,9 +134,3 @@ .monaco-workbench .repl .repl-tree .output.expression .code-bold { font-weight: bold; } .monaco-workbench .repl .repl-tree .output.expression .code-italic { font-style: italic; } .monaco-workbench .repl .repl-tree .output.expression .code-underline { text-decoration: underline; } - -/* Links */ -.monaco-workbench .repl .repl-tree .output.expression a { - text-decoration: underline; - cursor: pointer; -} diff --git a/src/vs/workbench/contrib/debug/browser/media/restart-white.svg b/src/vs/workbench/contrib/debug/browser/media/restart-white.svg new file mode 100644 index 0000000000..cf498da0c7 --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/restart-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/step-into-white.svg b/src/vs/workbench/contrib/debug/browser/media/step-into-white.svg new file mode 100644 index 0000000000..77ef1cbf34 --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/step-into-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/step-out-white.svg b/src/vs/workbench/contrib/debug/browser/media/step-out-white.svg new file mode 100644 index 0000000000..906cd8d33c --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/step-out-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/step-over-white.svg b/src/vs/workbench/contrib/debug/browser/media/step-over-white.svg new file mode 100644 index 0000000000..bac3022c88 --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/step-over-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/stop-white.svg b/src/vs/workbench/contrib/debug/browser/media/stop-white.svg new file mode 100644 index 0000000000..f33eb6181d --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/stop-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts index 440ecee010..1dcb9efe4f 100644 --- a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts @@ -18,6 +18,8 @@ import { URI } from 'vs/base/common/uri'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { env as processEnv } from 'vs/base/common/process'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { CancellationToken } from 'vs/base/common/cancellation'; /** * This interface represents a single command line argument split into a "prefix" and a "path" half. @@ -37,7 +39,7 @@ interface ILaunchVSCodeArguments { /** * Encapsulates the DebugAdapter lifecycle and some idiosyncrasies of the Debug Adapter Protocol. */ -export class RawDebugSession { +export class RawDebugSession implements IDisposable { private allThreadsContinued = true; private _readyForBreakpoints = false; @@ -70,6 +72,8 @@ export class RawDebugSession { private readonly _onDidExitAdapter: Emitter; private debugAdapter: IDebugAdapter | null; + private toDispose: IDisposable[] = []; + constructor( debugAdapter: IDebugAdapter, dbgr: IDebugger, @@ -96,18 +100,18 @@ export class RawDebugSession { this._onDidExitAdapter = new Emitter(); - this.debugAdapter.onError(err => { + this.toDispose.push(this.debugAdapter.onError(err => { this.shutdown(err); - }); + })); - this.debugAdapter.onExit(code => { + this.toDispose.push(this.debugAdapter.onExit(code => { if (code !== 0) { this.shutdown(new Error(`exit code: ${code}`)); } else { // normal exit this.shutdown(); } - }); + })); this.debugAdapter.onEvent(event => { switch (event.event) { @@ -341,9 +345,9 @@ export class RawDebugSession { return Promise.reject(new Error('restartFrame not supported')); } - completions(args: DebugProtocol.CompletionsArguments): Promise { + completions(args: DebugProtocol.CompletionsArguments, token: CancellationToken): Promise { if (this.capabilities.supportsCompletionsRequest) { - return this.send('completions', args); + return this.send('completions', args, token); } return Promise.reject(new Error('completions not supported')); } @@ -384,8 +388,8 @@ export class RawDebugSession { return Promise.reject(new Error('configurationDone not supported')); } - stackTrace(args: DebugProtocol.StackTraceArguments): Promise { - return this.send('stackTrace', args); + stackTrace(args: DebugProtocol.StackTraceArguments, token: CancellationToken): Promise { + return this.send('stackTrace', args, token); } exceptionInfo(args: DebugProtocol.ExceptionInfoArguments): Promise { @@ -395,12 +399,12 @@ export class RawDebugSession { return Promise.reject(new Error('exceptionInfo not supported')); } - scopes(args: DebugProtocol.ScopesArguments): Promise { - return this.send('scopes', args); + scopes(args: DebugProtocol.ScopesArguments, token: CancellationToken): Promise { + return this.send('scopes', args, token); } - variables(args: DebugProtocol.VariablesArguments): Promise { - return this.send('variables', args); + variables(args: DebugProtocol.VariablesArguments, token?: CancellationToken): Promise { + return this.send('variables', args, token); } source(args: DebugProtocol.SourceArguments): Promise { @@ -463,18 +467,21 @@ export class RawDebugSession { return Promise.reject(new Error('goto is not supported')); } + cancel(args: DebugProtocol.CancelArguments): Promise { + return this.send('cancel', args); + } + custom(request: string, args: any): Promise { return this.send(request, args); } //---- private - private shutdown(error?: Error, restart = false): Promise { if (!this.inShutdown) { this.inShutdown = true; if (this.debugAdapter) { - return this.send('disconnect', { restart }, 500).then(() => { + return this.send('disconnect', { restart }, undefined, 500).then(() => { this.stopAdapter(error); }, () => { // ignore error @@ -583,15 +590,17 @@ export class RawDebugSession { const v = args[key]; if (v) { - if (Array.isArray(v)) { - v.push(value); - } else { - args[key] = [v, value]; - } + v.push(value); } else { - args[key] = value; + args[key] = [value]; + } + } else if (key === 'extensionDevelopmentPath') { + const v = args[key]; + if (v) { + v.push(value); + } else { + args[key] = [value]; } - } else { (args)[key] = value; } @@ -619,20 +628,34 @@ export class RawDebugSession { return this.windowsService.openExtensionDevelopmentHostWindow(args, env); } - private send(command: string, args: any, timeout?: number): Promise { + private send(command: string, args: any, token?: CancellationToken, timeout?: number): Promise { return new Promise((completeDispatch, errorDispatch) => { if (!this.debugAdapter) { errorDispatch(new Error('no debug adapter found')); return; } - this.debugAdapter.sendRequest(command, args, (response: R) => { + let cancelationListener: IDisposable; + const requestId = this.debugAdapter.sendRequest(command, args, (response: R) => { + if (cancelationListener) { + cancelationListener.dispose(); + } + if (response.success) { completeDispatch(response); } else { errorDispatch(response); } }, timeout); - }).then(response => response, err => Promise.reject(this.handleErrorResponse(err))); + + if (token) { + cancelationListener = token.onCancellationRequested(() => { + cancelationListener.dispose(); + if (this.capabilities.supportsCancelRequest) { + this.cancel({ requestId }); + } + }); + } + }).then(undefined, err => Promise.reject(this.handleErrorResponse(err))); } private handleErrorResponse(errorResponse: DebugProtocol.Response): Error { @@ -696,4 +719,8 @@ export class RawDebugSession { this.customTelemetryService.publicLog('debugProtocolErrorResponse', { error: telemetryMessage }); } } + + dispose(): void { + dispose(this.toDispose); + } } diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index d091e18538..88dd5edeb7 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -44,25 +44,25 @@ import { CompletionContext, CompletionList, CompletionProviderRegistry } from 'v import { first } from 'vs/base/common/arrays'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; -import { Variable, Expression, SimpleReplElement, RawObjectReplElement } from 'vs/workbench/contrib/debug/common/debugModel'; +import { Variable } from 'vs/workbench/contrib/debug/common/debugModel'; +import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplEvaluationResult } from 'vs/workbench/contrib/debug/common/replModel'; import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { ITreeRenderer, ITreeNode, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { renderExpressionValue } from 'vs/workbench/contrib/debug/browser/baseDebugView'; +import { renderExpressionValue, AbstractExpressionsRenderer, IExpressionTemplateData, renderVariable, IInputBoxOptions } from 'vs/workbench/contrib/debug/browser/baseDebugView'; import { handleANSIOutput } from 'vs/workbench/contrib/debug/browser/debugANSIHandling'; import { ILabelService } from 'vs/platform/label/common/label'; import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { removeAnsiEscapeCodes } from 'vs/base/common/strings'; import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; import { RunOnceScheduler } from 'vs/base/common/async'; import { FuzzyScore, createMatches } from 'vs/base/common/filters'; -import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; +import { HighlightedLabel, IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import { VariablesRenderer } from 'vs/workbench/contrib/debug/browser/variablesView'; const $ = dom.$; @@ -71,7 +71,7 @@ const IPrivateReplService = createDecorator('privateReplSer const DECORATION_KEY = 'replinputdecoration'; interface IPrivateReplService { - _serviceBrand: any; + _serviceBrand: undefined; acceptReplInput(): void; getVisibleContent(): string; selectSession(session?: IDebugSession): void; @@ -85,7 +85,7 @@ function revealLastElement(tree: WorkbenchAsyncDataTree) { const sessionsToIgnore = new Set(); export class Repl extends Panel implements IPrivateReplService, IHistoryNavigationWidget { - _serviceBrand: any; + _serviceBrand: undefined; private static readonly REFRESH_DELAY = 100; // delay in ms to refresh the repl for new elements to show private static readonly REPL_INPUT_INITIAL_HEIGHT = 19; @@ -149,7 +149,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati const text = model.getLineContent(position.lineNumber); const focusedStackFrame = this.debugService.getViewModel().focusedStackFrame; const frameId = focusedStackFrame ? focusedStackFrame.frameId : undefined; - const suggestions = await session.completions(frameId, text, position, overwriteBefore); + const suggestions = await session.completions(frameId, text, position, overwriteBefore, token); return { suggestions }; } @@ -404,15 +404,18 @@ 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); + const linkDetector = this.instantiationService.createInstance(LinkDetector); this.tree = this.instantiationService.createInstance( WorkbenchAsyncDataTree, + 'DebugRepl', treeContainer, this.replDelegate, [ - this.instantiationService.createInstance(VariablesRenderer), - this.instantiationService.createInstance(ReplSimpleElementsRenderer), - new ReplExpressionsRenderer(), - new ReplRawObjectsRenderer() + this.instantiationService.createInstance(ReplVariablesRenderer, linkDetector), + this.instantiationService.createInstance(ReplSimpleElementsRenderer, linkDetector), + new ReplEvaluationInputsRenderer(), + new ReplEvaluationResultsRenderer(linkDetector), + new ReplRawObjectsRenderer(linkDetector), ], // https://github.com/microsoft/TypeScript/issues/32526 new ReplDataSource() as IAsyncDataSource, @@ -444,7 +447,6 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati private createReplInput(container: HTMLElement): void { this.replInputContainer = dom.append(container, $('.repl-input-wrapper')); - this.replInputContainer.title = nls.localize('debugConsole', "Debug Console"); const { scopedContextKeyService, historyNavigationEnablement } = createAndBindHistoryNavigationWidgetScopedContextKeyService(this.contextKeyService, { target: this.replInputContainer, historyNavigator: this }); this.historyNavigationEnablement = historyNavigationEnablement; @@ -455,6 +457,8 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati [IContextKeyService, scopedContextKeyService], [IPrivateReplService, this])); const options = getSimpleEditorOptions(); options.readOnly = true; + options.ariaLabel = nls.localize('debugConsole', "Debug Console"); + this.replInput = this.scopedInstantiationService.createInstance(CodeEditorWidget, this.replInputContainer, options, getSimpleCodeEditorWidgetOptions()); this._register(this.replInput.onDidScrollChange(e => { @@ -566,12 +570,13 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati // Repl tree -interface IExpressionTemplateData { - input: HTMLElement; - output: HTMLElement; +interface IReplEvaluationInputTemplateData { + label: HighlightedLabel; +} + +interface IReplEvaluationResultTemplateData { value: HTMLElement; annotation: HTMLElement; - label: HighlightedLabel; } interface ISimpleReplElementTemplateData { @@ -591,31 +596,53 @@ interface IRawObjectReplTemplateData { label: HighlightedLabel; } -class ReplExpressionsRenderer implements ITreeRenderer { - static readonly ID = 'expressionRepl'; +class ReplEvaluationInputsRenderer implements ITreeRenderer { + static readonly ID = 'replEvaluationInput'; get templateId(): string { - return ReplExpressionsRenderer.ID; + return ReplEvaluationInputsRenderer.ID; } - renderTemplate(container: HTMLElement): IExpressionTemplateData { - dom.addClass(container, 'input-output-pair'); - const input = dom.append(container, $('.input.expression')); + renderTemplate(container: HTMLElement): IReplEvaluationInputTemplateData { + const input = dom.append(container, $('.expression')); const label = new HighlightedLabel(input, false); - const output = dom.append(container, $('.output.expression')); + return { label }; + } + + renderElement(element: ITreeNode, index: number, templateData: IReplEvaluationInputTemplateData): void { + const evaluation = element.element; + templateData.label.set(evaluation.value, createMatches(element.filterData)); + } + + disposeTemplate(templateData: IReplEvaluationInputTemplateData): void { + // noop + } +} + +class ReplEvaluationResultsRenderer implements ITreeRenderer { + static readonly ID = 'replEvaluationResult'; + + get templateId(): string { + return ReplEvaluationResultsRenderer.ID; + } + + constructor(private readonly linkDetector: LinkDetector) { } + + renderTemplate(container: HTMLElement): IReplEvaluationResultTemplateData { + const output = dom.append(container, $('.evaluation-result.expression')); const value = dom.append(output, $('span.value')); const annotation = dom.append(output, $('span')); - return { input, label, output, value, annotation }; + return { value, annotation }; } - renderElement(element: ITreeNode, index: number, templateData: IExpressionTemplateData): void { + renderElement(element: ITreeNode, index: number, templateData: IReplEvaluationResultTemplateData): void { const expression = element.element; - templateData.label.set(expression.name, createMatches(element.filterData)); renderExpressionValue(expression, templateData.value, { preserveWhitespace: !expression.hasChildren, showHover: false, - colorize: true + colorize: true, + linkDetector: this.linkDetector }); if (expression.hasChildren) { templateData.annotation.className = 'annotation octicon octicon-info'; @@ -623,7 +650,7 @@ class ReplExpressionsRenderer implements ITreeRenderer { static readonly ID = 'rawObject'; + constructor(private readonly linkDetector: LinkDetector) { } + get templateId(): string { return ReplRawObjectsRenderer.ID; } @@ -724,7 +774,8 @@ class ReplRawObjectsRenderer implements ITreeRenderer { const rowHeight = Math.ceil(1.4 * fontSize); const wordWrap = config.console.wordWrap; if (!wordWrap) { - return element instanceof Expression ? 2 * rowHeight : rowHeight; + return rowHeight; } // In order to keep scroll position we need to give a good approximation to the tree // For every 150 characters increase the number of lines needed - if (element instanceof Expression) { - let { name, value } = element; - let nameRows = countNumberOfLines(name) + Math.floor(name.length / 150); + if (element instanceof ReplEvaluationResult) { + let value = element.value; if (element.hasChildren) { - return (nameRows + 1) * rowHeight; + return rowHeight; } let valueRows = value ? (countNumberOfLines(value) + Math.floor(value.length / 150)) : 0; - return rowHeight * (nameRows + valueRows); + return rowHeight * valueRows; } - if (element instanceof SimpleReplElement) { + if (element instanceof SimpleReplElement || element instanceof ReplEvaluationInput) { let value = element.value; let valueRows = countNumberOfLines(value) + Math.floor(value.length / 150); @@ -784,10 +834,13 @@ class ReplDelegate implements IListVirtualDelegate { getTemplateId(element: IReplElement): string { if (element instanceof Variable && element.name) { - return VariablesRenderer.ID; + return ReplVariablesRenderer.ID; } - if (element instanceof Expression) { - return ReplExpressionsRenderer.ID; + if (element instanceof ReplEvaluationResult) { + return ReplEvaluationResultsRenderer.ID; + } + if (element instanceof ReplEvaluationInput) { + return ReplEvaluationInputsRenderer.ID; } if (element instanceof SimpleReplElement || (element instanceof Variable && !element.name)) { // Variable with no name is a top level variable which should be rendered like a repl element #17404 @@ -834,10 +887,7 @@ class ReplAccessibilityProvider implements IAccessibilityProvider if (element instanceof Variable) { return nls.localize('replVariableAriaLabel', "Variable {0} has value {1}, read eval print loop, debug", element.name, element.value); } - if (element instanceof Expression) { - return nls.localize('replExpressionAriaLabel', "Expression {0} has value {1}, read eval print loop, debug", element.name, element.value); - } - if (element instanceof SimpleReplElement) { + if (element instanceof SimpleReplElement || element instanceof ReplEvaluationInput || element instanceof ReplEvaluationResult) { return nls.localize('replValueOutputAriaLabel', "{0}, read eval print loop, debug", element.value); } if (element instanceof RawObjectReplElement) { diff --git a/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts index 7feec60896..625808128e 100644 --- a/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts +++ b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts @@ -70,9 +70,13 @@ export class StatusBarColorProvider extends Themable implements IWorkbenchContri // Border Color const borderColor = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_BORDER, STATUS_BAR_DEBUGGING_BORDER, STATUS_BAR_BORDER)) || this.getColor(contrastBorder); - container.style.borderTopWidth = borderColor ? '1px' : null; - container.style.borderTopStyle = borderColor ? 'solid' : null; - container.style.borderTopColor = borderColor; + if (borderColor) { + addClass(container, 'status-border-top'); + container.style.setProperty('--status-border-top-color', borderColor.toString()); + } else { + removeClass(container, 'status-border-top'); + container.style.removeProperty('--status-border-top-color'); + } // Notification Beak if (!this.styleElement) { diff --git a/src/vs/workbench/contrib/debug/browser/variablesView.ts b/src/vs/workbench/contrib/debug/browser/variablesView.ts index 1f3761eec3..de88d3a723 100644 --- a/src/vs/workbench/contrib/debug/browser/variablesView.ts +++ b/src/vs/workbench/contrib/debug/browser/variablesView.ts @@ -86,14 +86,14 @@ export class VariablesView extends ViewletPanel { dom.addClass(container, 'debug-variables'); const treeContainer = renderViewTree(container); - this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, treeContainer, new VariablesDelegate(), + this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'VariablesView', treeContainer, new VariablesDelegate(), [this.instantiationService.createInstance(VariablesRenderer), new ScopesRenderer()], new VariablesDataSource(), { - ariaLabel: nls.localize('variablesAriaTreeLabel', "Debug Variables"), - accessibilityProvider: new VariablesAccessibilityProvider(), - identityProvider: { getId: (element: IExpression | IScope) => element.getId() }, - keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IExpression | IScope) => e } - }); + ariaLabel: nls.localize('variablesAriaTreeLabel', "Debug Variables"), + accessibilityProvider: new VariablesAccessibilityProvider(), + identityProvider: { getId: (element: IExpression | IScope) => element.getId() }, + keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IExpression | IScope) => e } + }); this.tree.setInput(this.debugService.getViewModel()).then(null, onUnexpectedError); @@ -179,7 +179,7 @@ export class VariablesView extends ViewletPanel { const dataid = response.dataId; if (dataid) { actions.push(new Separator()); - actions.push(new Action('debug.addDataBreakpoint', nls.localize('setDataBreakpoint', "Set Data Breakpoint"), undefined, true, () => { + actions.push(new Action('debug.breakWhenValueChanges', nls.localize('breakWhenValueChanges', "Break When Value Changes"), undefined, true, () => { return this.debugService.addDataBreakpoint(response.description, dataid, !!response.canPersist); })); } diff --git a/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts b/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts index d913bb4db6..9d8e37aaba 100644 --- a/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts +++ b/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts @@ -61,14 +61,14 @@ export class WatchExpressionsView extends ViewletPanel { const treeContainer = renderViewTree(container); const expressionsRenderer = this.instantiationService.createInstance(WatchExpressionsRenderer); - this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, treeContainer, new WatchExpressionsDelegate(), [expressionsRenderer, this.instantiationService.createInstance(VariablesRenderer)], + this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'WatchExpressions', treeContainer, new WatchExpressionsDelegate(), [expressionsRenderer, this.instantiationService.createInstance(VariablesRenderer)], new WatchExpressionsDataSource(), { - ariaLabel: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'watchAriaTreeLabel' }, "Debug Watch Expressions"), - accessibilityProvider: new WatchExpressionsAccessibilityProvider(), - identityProvider: { getId: (element: IExpression) => element.getId() }, - keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IExpression) => e }, - dnd: new WatchExpressionsDragAndDrop(this.debugService), - }); + ariaLabel: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'watchAriaTreeLabel' }, "Debug Watch Expressions"), + accessibilityProvider: new WatchExpressionsAccessibilityProvider(), + identityProvider: { getId: (element: IExpression) => element.getId() }, + keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IExpression) => e }, + dnd: new WatchExpressionsDragAndDrop(this.debugService), + }); 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/abstractDebugAdapter.ts b/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts index bc53d3b9f1..5c0c4ed2d7 100644 --- a/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts +++ b/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts @@ -5,6 +5,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IDebugAdapter } from 'vs/workbench/contrib/debug/common/debug'; +import { timeout } from 'vs/base/common/async'; /** * Abstract implementation of the low level API for a debug adapter. @@ -70,7 +71,7 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter { } } - sendRequest(command: string, args: any, clb: (result: DebugProtocol.Response) => void, timeout?: number): void { + sendRequest(command: string, args: any, clb: (result: DebugProtocol.Response) => void, timeout?: number): number { const request: any = { command: command }; @@ -100,6 +101,8 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter { // store callback for this request this.pendingRequests.set(request.seq, clb); } + + return request.seq; } acceptMessage(message: DebugProtocol.ProtocolMessage): void { @@ -136,25 +139,33 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter { this.sendMessage(message); } - protected cancelPending() { - const pending = this.pendingRequests; - this.pendingRequests.clear(); - setTimeout(_ => { - pending.forEach((callback, request_seq) => { - const err: DebugProtocol.Response = { - type: 'response', - seq: 0, - request_seq, - success: false, - command: 'canceled', - message: 'canceled' - }; - callback(err); - }); - }, 1000); + protected async cancelPendingRequests(): Promise { + if (this.pendingRequests.size === 0) { + return Promise.resolve(); + } + + const pending = new Map void>(); + this.pendingRequests.forEach((value, key) => pending.set(key, value)); + await timeout(500); + pending.forEach((callback, request_seq) => { + const err: DebugProtocol.Response = { + type: 'response', + seq: 0, + request_seq, + success: false, + command: 'canceled', + message: 'canceled' + }; + callback(err); + this.pendingRequests.delete(request_seq); + }); + } + + getPendingRequestIds(): number[] { + return Array.from(this.pendingRequests.keys()); } dispose(): void { - this.cancelPending(); + // noop } } diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index b11ec4ccd1..76c476e101 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -104,13 +104,13 @@ export interface IExpressionContainer extends ITreeElement { readonly hasChildren: boolean; getChildren(): Promise; readonly reference?: number; + readonly value: string; + readonly type?: string; + valueChanged?: boolean; } -export interface IExpression extends IReplElement, IExpressionContainer { +export interface IExpression extends IExpressionContainer { name: string; - readonly value: string; - valueChanged?: boolean; - readonly type?: string; } export interface IDebugger { @@ -157,6 +157,8 @@ export interface IDebugSession extends ITreeElement { setSubId(subId: string | undefined): void; + setName(name: string): void; + readonly onDidChangeName: Event; getLabel(): string; getSourceForUri(modelUri: uri): Source | undefined; @@ -208,8 +210,8 @@ export interface IDebugSession extends ITreeElement { stackTrace(threadId: number, startFrame: number, levels: number): Promise; exceptionInfo(threadId: number): Promise; - scopes(frameId: number): Promise; - variables(variablesReference: number, filter: 'indexed' | 'named' | undefined, start: number | undefined, count: number | undefined): Promise; + scopes(frameId: number, threadId: number): Promise; + variables(variablesReference: number, threadId: number | undefined, filter: 'indexed' | 'named' | undefined, start: number | undefined, count: number | undefined): Promise; evaluate(expression: string, frameId?: number, context?: string): Promise; customRequest(request: string, args: any): Promise; @@ -223,7 +225,7 @@ export interface IDebugSession extends ITreeElement { pause(threadId: number): Promise; terminateThreads(threadIds: number[]): Promise; - completions(frameId: number | undefined, text: string, position: Position, overwriteBefore: number): Promise; + completions(frameId: number | undefined, text: string, position: Position, overwriteBefore: number, token: CancellationToken): Promise; setVariable(variablesReference: number | undefined, name: string, value: string): Promise; loadSource(resource: uri): Promise; getLoadedSources(): Promise; @@ -308,6 +310,7 @@ export interface IStackFrame extends ITreeElement { restart(): Promise; toString(): string; openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean): Promise; + equals(other: IStackFrame): boolean; } export interface IEnablement extends ITreeElement { @@ -337,7 +340,7 @@ export interface IBaseBreakpoint extends IEnablement { readonly hitCondition?: string; readonly logMessage?: string; readonly verified: boolean; - readonly idFromAdapter: number | undefined; + getIdFromAdapter(sessionId: string): number | undefined; } export interface IBreakpoint extends IBaseBreakpoint { @@ -452,6 +455,7 @@ export interface IDebugConfiguration { wordWrap: boolean; }; focusWindowOnBreak: boolean; + onTaskErrors: 'debugAnyway' | 'showErrors' | 'prompt'; } export interface IGlobalConfig { @@ -500,7 +504,7 @@ export interface IDebugAdapter extends IDisposable { startSession(): Promise; sendMessage(message: DebugProtocol.ProtocolMessage): void; sendResponse(response: DebugProtocol.Response): void; - sendRequest(command: string, args: any, clb: (result: DebugProtocol.Response) => void, timeout?: number): void; + sendRequest(command: string, args: any, clb: (result: DebugProtocol.Response) => void, timeout?: number): number; stopSession(): Promise; } @@ -682,7 +686,7 @@ export interface ILaunch { export const IDebugService = createDecorator(DEBUG_SERVICE_ID); export interface IDebugService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Gets the current debug state. @@ -857,7 +861,7 @@ export const DEBUG_HELPER_SERVICE_ID = 'debugHelperService'; export const IDebugHelperService = createDecorator(DEBUG_HELPER_SERVICE_ID); export interface IDebugHelperService { - _serviceBrand: any; + _serviceBrand: undefined; createTelemetryService(configurationService: IConfigurationService, args: string[]): TelemetryService | undefined; } diff --git a/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts index f778ae187c..0598be46a8 100644 --- a/src/vs/workbench/contrib/debug/common/debugModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugModel.ts @@ -10,13 +10,12 @@ import * as lifecycle from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import { generateUuid } from 'vs/base/common/uuid'; import { RunOnceScheduler } from 'vs/base/common/async'; -import severity from 'vs/base/common/severity'; -import { isObject, isString, isUndefinedOrNull } from 'vs/base/common/types'; +import { isString, isUndefinedOrNull } from 'vs/base/common/types'; import { distinct, lastIndex } from 'vs/base/common/arrays'; import { Range, IRange } from 'vs/editor/common/core/range'; import { - ITreeElement, IExpression, IExpressionContainer, IDebugSession, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IDebugModel, IReplElementSource, - IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IBreakpointData, IExceptionInfo, IReplElement, IBreakpointsChangeEvent, IBreakpointUpdateData, IBaseBreakpoint, State, IDataBreakpoint + ITreeElement, IExpression, IExpressionContainer, IDebugSession, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IDebugModel, + IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IBreakpointData, IExceptionInfo, IBreakpointsChangeEvent, IBreakpointUpdateData, IBaseBreakpoint, State, IDataBreakpoint } from 'vs/workbench/contrib/debug/common/debug'; import { Source, UNKNOWN_SOURCE_LABEL } from 'vs/workbench/contrib/debug/common/debugSource'; import { commonSuffixLength } from 'vs/base/common/strings'; @@ -25,81 +24,20 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ITextEditor } from 'vs/workbench/common/editor'; -export class SimpleReplElement implements IReplElement { - constructor( - private id: string, - public value: string, - public severity: severity, - public sourceData?: IReplElementSource, - ) { } - - toString(): string { - return this.value; - } - - getId(): string { - return this.id; - } -} - -export class RawObjectReplElement implements IExpression { - - private static readonly MAX_CHILDREN = 1000; // upper bound of children per value - - constructor(private id: string, public name: string, public valueObj: any, public sourceData?: IReplElementSource, public annotation?: string) { } - - getId(): string { - return this.id; - } - - get value(): string { - if (this.valueObj === null) { - return 'null'; - } else if (Array.isArray(this.valueObj)) { - return `Array[${this.valueObj.length}]`; - } else if (isObject(this.valueObj)) { - return 'Object'; - } else if (isString(this.valueObj)) { - return `"${this.valueObj}"`; - } - - return String(this.valueObj) || ''; - } - - get hasChildren(): boolean { - return (Array.isArray(this.valueObj) && this.valueObj.length > 0) || (isObject(this.valueObj) && Object.getOwnPropertyNames(this.valueObj).length > 0); - } - - getChildren(): Promise { - let result: IExpression[] = []; - if (Array.isArray(this.valueObj)) { - result = (this.valueObj).slice(0, RawObjectReplElement.MAX_CHILDREN) - .map((v, index) => new RawObjectReplElement(`${this.id}:${index}`, String(index), v)); - } else if (isObject(this.valueObj)) { - result = Object.getOwnPropertyNames(this.valueObj).slice(0, RawObjectReplElement.MAX_CHILDREN) - .map((key, index) => new RawObjectReplElement(`${this.id}:${index}`, key, this.valueObj[key])); - } - - return Promise.resolve(result); - } - - toString(): string { - return `${this.name}\n${this.value}`; - } -} - export class ExpressionContainer implements IExpressionContainer { public static allValues = new Map(); // Use chunks to support variable paging #9537 private static readonly BASE_CHUNK_SIZE = 100; + public type: string | undefined; public valueChanged = false; private _value: string = ''; protected children?: Promise; constructor( protected session: IDebugSession | undefined, + protected threadId: number | undefined, private _reference: number | undefined, private id: string, public namedVariables: number | undefined = 0, @@ -148,7 +86,7 @@ export class ExpressionContainer implements IExpressionContainer { for (let i = 0; i < numberOfChunks; i++) { const start = (this.startOfVariables || 0) + i * chunkSize; const count = Math.min(chunkSize, this.indexedVariables - i * chunkSize); - children.push(new Variable(this.session, this, this.reference, `[${start}..${start + count - 1}]`, '', '', undefined, count, { kind: 'virtual' }, undefined, true, start)); + children.push(new Variable(this.session, this.threadId, this, this.reference, `[${start}..${start + count - 1}]`, '', '', undefined, count, { kind: 'virtual' }, undefined, true, start)); } return children; @@ -172,12 +110,12 @@ export class ExpressionContainer implements IExpressionContainer { } private fetchVariables(start: number | undefined, count: number | undefined, filter: 'indexed' | 'named' | undefined): Promise { - return this.session!.variables(this.reference || 0, filter, start, count).then(response => { + return this.session!.variables(this.reference || 0, this.threadId, filter, start, count).then(response => { return response && response.body && response.body.variables ? distinct(response.body.variables.filter(v => !!v && isString(v.name)), (v: DebugProtocol.Variable) => v.name).map((v: DebugProtocol.Variable) => - new Variable(this.session, this, v.variablesReference, v.name, v.evaluateName, v.value, v.namedVariables, v.indexedVariables, v.presentationHint, v.type)) + new Variable(this.session, this.threadId, this, v.variablesReference, v.name, v.evaluateName, v.value, v.namedVariables, v.indexedVariables, v.presentationHint, v.type)) : []; - }, (e: Error) => [new Variable(this.session, this, 0, e.message, e.message, '', 0, 0, { kind: 'virtual' }, undefined, false)]); + }, (e: Error) => [new Variable(this.session, this.threadId, this, 0, e.message, e.message, '', 0, 0, { kind: 'virtual' }, undefined, false)]); } // The adapter explicitly sents the children count of an expression only if there are lots of children which should be chunked. @@ -195,16 +133,46 @@ export class ExpressionContainer implements IExpressionContainer { toString(): string { return this.value; } + + async evaluateExpression( + expression: string, + session: IDebugSession | undefined, + stackFrame: IStackFrame | undefined, + context: string): Promise { + + if (!session || (!stackFrame && context !== 'repl')) { + this.value = context === 'repl' ? nls.localize('startDebugFirst', "Please start a debug session to evaluate expressions") : Expression.DEFAULT_VALUE; + this.reference = 0; + return false; + } + + this.session = session; + try { + const response = await session.evaluate(expression, stackFrame ? stackFrame.frameId : undefined, context); + if (response && response.body) { + this.value = response.body.result || ''; + this.reference = response.body.variablesReference; + this.namedVariables = response.body.namedVariables; + this.indexedVariables = response.body.indexedVariables; + this.type = response.body.type || this.type; + return true; + } + return false; + } catch (e) { + this.value = e.message || ''; + this.reference = 0; + return false; + } + } } export class Expression extends ExpressionContainer implements IExpression { static DEFAULT_VALUE = nls.localize('notAvailable', "not available"); public available: boolean; - public type: string | undefined; constructor(public name: string, id = generateUuid()) { - super(undefined, 0, id); + super(undefined, undefined, 0, id); this.available = false; // name is not set if the expression is just being added // in that case do not set default value to prevent flashing #14499 @@ -214,30 +182,7 @@ export class Expression extends ExpressionContainer implements IExpression { } async evaluate(session: IDebugSession | undefined, stackFrame: IStackFrame | undefined, context: string): Promise { - if (!session || (!stackFrame && context !== 'repl')) { - this.value = context === 'repl' ? nls.localize('startDebugFirst', "Please start a debug session to evaluate expressions") : Expression.DEFAULT_VALUE; - this.available = false; - this.reference = 0; - - return Promise.resolve(undefined); - } - - this.session = session; - try { - const response = await session.evaluate(this.name, stackFrame ? stackFrame.frameId : undefined, context); - this.available = !!(response && response.body); - if (response && response.body) { - this.value = response.body.result || ''; - this.reference = response.body.variablesReference; - this.namedVariables = response.body.namedVariables; - this.indexedVariables = response.body.indexedVariables; - this.type = response.body.type || this.type; - } - } catch (e) { - this.value = e.message || ''; - this.available = false; - this.reference = 0; - } + this.available = await this.evaluateExpression(this.name, session, stackFrame, context); } toString(): string { @@ -252,6 +197,7 @@ export class Variable extends ExpressionContainer implements IExpression { constructor( session: IDebugSession | undefined, + threadId: number | undefined, public parent: IExpressionContainer, reference: number | undefined, public name: string, @@ -264,7 +210,7 @@ export class Variable extends ExpressionContainer implements IExpression { public available = true, startOfVariables = 0 ) { - super(session, reference, `variable:${parent.getId()}:${name}`, namedVariables, indexedVariables, startOfVariables); + super(session, threadId, reference, `variable:${parent.getId()}:${name}`, namedVariables, indexedVariables, startOfVariables); this.value = value || ''; } @@ -304,7 +250,7 @@ export class Scope extends ExpressionContainer implements IScope { indexedVariables?: number, public range?: IRange ) { - super(stackFrame.thread.session, reference, `scope:${name}:${index}`, namedVariables, indexedVariables); + super(stackFrame.thread.session, stackFrame.thread.threadId, reference, `scope:${name}:${index}`, namedVariables, indexedVariables); } toString(): string { @@ -332,7 +278,7 @@ export class StackFrame implements IStackFrame { getScopes(): Promise { if (!this.scopes) { - this.scopes = this.thread.session.scopes(this.frameId).then(response => { + this.scopes = this.thread.session.scopes(this.frameId, this.thread.threadId).then(response => { return response && response.body && response.body.scopes ? response.body.scopes.map((rs, index) => new Scope(this, index, rs.name, rs.variablesReference, rs.expensive, rs.namedVariables, rs.indexedVariables, rs.line && rs.column && rs.endLine && rs.endColumn ? new Range(rs.line, rs.column, rs.endLine, rs.endColumn) : undefined)) : []; @@ -395,6 +341,10 @@ export class StackFrame implements IStackFrame { return !this.source.available ? Promise.resolve(null) : this.source.openInEditor(editorService, this.range, preserveFocus, sideBySide, pinned); } + + equals(other: IStackFrame): boolean { + return (this.name === other.name) && (other.thread === this.thread) && (other.source === this.source) && (Range.equalsRange(this.range, other.range)); + } } export class Thread implements IThread { @@ -578,13 +528,22 @@ export class BaseBreakpoint extends Enablement implements IBaseBreakpoint { this.sessionId = sessionId; } + get message(): string | undefined { + const data = this.getSessionData(); + if (!data) { + return undefined; + } + + return data.message; + } + get verified(): boolean { const data = this.getSessionData(); return data ? data.verified : true; } - get idFromAdapter(): number | undefined { - const data = this.getSessionData(); + getIdFromAdapter(sessionId: string): number | undefined { + const data = this.sessionData.get(sessionId); return data ? data.id : undefined; } @@ -637,15 +596,11 @@ export class Breakpoint extends BaseBreakpoint implements IBreakpoint { } get message(): string | undefined { - const data = this.getSessionData(); - if (!data) { - return undefined; - } if (this.textFileService.isDirty(this.uri)) { return nls.localize('breakpointDirtydHover', "Unverified breakpoint. File is modified, please restart debug session."); } - return data.message; + return super.message; } get adapterData(): any { @@ -797,13 +752,13 @@ export class DebugModel implements IDebugModel { private toDispose: lifecycle.IDisposable[]; private schedulers = new Map(); private breakpointsSessionId: string | undefined; + private breakpointsActivated = true; private readonly _onDidChangeBreakpoints: Emitter; private readonly _onDidChangeCallStack: Emitter; private readonly _onDidChangeWatchExpressions: Emitter; constructor( private breakpoints: Breakpoint[], - private breakpointsActivated: boolean, private functionBreakpoints: FunctionBreakpoint[], private exceptionBreakpoints: ExceptionBreakpoint[], private dataBreakopints: DataBreakpoint[], @@ -901,7 +856,16 @@ export class DebugModel implements IDebugModel { if (!this.schedulers.has(thread.getId())) { this.schedulers.set(thread.getId(), new RunOnceScheduler(() => { thread.fetchCallStack(19).then(() => { - this._onDidChangeCallStack.fire(); + const stale = thread.getStaleCallStack(); + const current = thread.getCallStack(); + let bottomOfCallStackChanged = stale.length !== current.length; + for (let i = 1; i < stale.length && !bottomOfCallStackChanged; i++) { + bottomOfCallStackChanged = !stale[i].equals(current[i]); + } + + if (bottomOfCallStackChanged) { + this._onDidChangeCallStack.fire(); + } c(); }); }, 420)); @@ -1065,9 +1029,9 @@ export class DebugModel implements IDebugModel { } setEnablement(element: IEnablement, enable: boolean): void { - if (element instanceof Breakpoint || element instanceof FunctionBreakpoint || element instanceof ExceptionBreakpoint) { - const changed: Array = []; - if (element.enabled !== enable && (element instanceof Breakpoint || element instanceof FunctionBreakpoint)) { + if (element instanceof Breakpoint || element instanceof FunctionBreakpoint || element instanceof ExceptionBreakpoint || element instanceof DataBreakpoint) { + const changed: Array = []; + if (element.enabled !== enable && (element instanceof Breakpoint || element instanceof FunctionBreakpoint || element instanceof DataBreakpoint)) { changed.push(element); } diff --git a/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts b/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts index a2376fe4d9..43b7922921 100644 --- a/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts +++ b/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts @@ -10,7 +10,7 @@ declare module DebugProtocol { /** Base class of requests, responses, and events. */ export interface ProtocolMessage { - /** Sequence number. */ + /** Sequence number (also known as message ID). For protocol messages of type 'request' this ID can be used to cancel the request. */ seq: number; /** Message type. Values: 'request', 'response', 'event', etc. @@ -41,11 +41,20 @@ declare module DebugProtocol { // type: 'response'; /** Sequence number of the corresponding request. */ request_seq: number; - /** Outcome of the request. */ + /** Outcome of the request. + If true, the request was successful and the 'body' attribute may contain the result of the request. + If the value is false, the attribute 'message' contains the error in short form and the 'body' may contain additional information (see 'ErrorResponse.body.error'). + */ success: boolean; /** The command requested. */ command: string; - /** Contains error message if success == false. */ + /** Contains the raw error in short form if 'success' is false. + This raw error might be interpreted by the frontend and is not shown in the UI. + Some predefined values exist. + Values: + 'cancelled': request was cancelled. + etc. + */ message?: string; /** Contains request result if success is true and optional error details if success is false. */ body?: any; @@ -59,6 +68,30 @@ declare module DebugProtocol { }; } + /** Cancel request; value of command field is 'cancel'. + The 'cancel' request is used by the frontend to indicate that it is no longer interested in the result produced by a specific request issued earlier. + This request has a hint characteristic: a debug adapter can only be expected to make a 'best effort' in honouring this request but there are no guarantees. + The 'cancel' request may return an error if it could not cancel an operation but a frontend should refrain from presenting this error to end users. + A frontend client should only call this request if the capability 'supportsCancelRequest' is true. + The request that got canceled still needs to send a response back. + This can either be a normal result ('success' attribute true) or an error response ('success' attribute false and the 'message' set to 'cancelled'). + Returning partial results from a cancelled request is possible but please note that a frontend client has no generic way for detecting that a response is partial or not. + */ + export interface CancelRequest extends Request { + // command: 'cancel'; + arguments?: CancelArguments; + } + + /** Arguments for 'cancel' request. */ + export interface CancelArguments { + /** The ID (attribute 'seq') of the request to cancel. */ + requestId?: number; + } + + /** Response to 'cancel' request. This is just an acknowledgement, so no body field is required. */ + export interface CancelResponse extends Response { + } + /** Event message for 'initialized' event type. This event indicates that the debug adapter is ready to accept configuration requests (e.g. SetBreakpointsRequest, SetExceptionBreakpointsRequest). A debug adapter is expected to send this event when it is ready to accept configuration requests (but not before the 'initialize' request has finished). @@ -455,6 +488,38 @@ declare module DebugProtocol { export interface TerminateResponse extends Response { } + /** BreakpointLocations request; value of command field is 'breakpointLocations'. + The 'breakpointLocations' request returns all possible locations for source breakpoints in a given range. + */ + export interface BreakpointLocationsRequest extends Request { + // command: 'breakpointLocations'; + arguments?: BreakpointLocationsArguments; + } + + /** Arguments for 'breakpointLocations' request. */ + export interface BreakpointLocationsArguments { + /** The source location of the breakpoints; either 'source.path' or 'source.reference' must be specified. */ + source: Source; + /** Start line of range to search possible breakpoint locations in. If only the line is specified, the request returns all possible locations in that line. */ + line: number; + /** Optional start column of range to search possible breakpoint locations in. If no start column is given, the first column in the start line is assumed. */ + column?: number; + /** Optional end line of range to search possible breakpoint locations in. If no end line is given, then the end line is assumed to be the start line. */ + endLine?: number; + /** Optional end column of range to search possible breakpoint locations in. If no end column is given, then it is assumed to be in the last column of the end line. */ + endColumn?: number; + } + + /** Response to 'breakpointLocations' request. + Contains possible locations for source breakpoints. + */ + export interface BreakpointLocationsResponse extends Response { + body: { + /** Sorted set of possible breakpoint locations. */ + breakpoints: BreakpointLocation[]; + }; + } + /** SetBreakpoints request; value of command field is 'setBreakpoints'. Sets multiple breakpoints for a single source and clears all previous breakpoints in that source. To clear all breakpoint for a source, specify an empty array. @@ -1330,6 +1395,10 @@ declare module DebugProtocol { supportsReadMemoryRequest?: boolean; /** The debug adapter supports the 'disassemble' request. */ supportsDisassembleRequest?: boolean; + /** The debug adapter supports the 'cancel' request. */ + supportsCancelRequest?: boolean; + /** The debug adapter supports the 'breakpointLocations' request. */ + supportsBreakpointLocationsRequest?: boolean; } /** An ExceptionBreakpointsFilter is shown in the UI as an option for configuring how exceptions are dealt with. */ @@ -1577,6 +1646,18 @@ declare module DebugProtocol { visibility?: string; } + /** Properties of a breakpoint location returned from the 'breakpointLocations' request. */ + export interface BreakpointLocation { + /** Start line of breakpoint location. */ + line: number; + /** Optional start column of breakpoint location. */ + column?: number; + /** Optional end line of breakpoint location if the location covers a range. */ + endLine?: number; + /** Optional end column of breakpoint location if the location covers a range. */ + endColumn?: number; + } + /** Properties of a breakpoint or logpoint passed to the setBreakpoints request. */ export interface SourceBreakpoint { /** The source line of the breakpoint or logpoint. */ diff --git a/src/vs/workbench/contrib/debug/common/debugSchemas.ts b/src/vs/workbench/contrib/debug/common/debugSchemas.ts index 67a43462e9..2e5cf3a16b 100644 --- a/src/vs/workbench/contrib/debug/common/debugSchemas.ts +++ b/src/vs/workbench/contrib/debug/common/debugSchemas.ts @@ -137,6 +137,8 @@ export const launchSchema: IJSONSchema = { id: launchSchemaId, type: 'object', title: nls.localize('app.launch.json.title', "Launch"), + allowsTrailingCommas: true, + allowComments: true, required: [], default: { version: '0.2.0', configurations: [], compounds: [] }, properties: { diff --git a/src/vs/workbench/contrib/debug/common/debugUtils.ts b/src/vs/workbench/contrib/debug/common/debugUtils.ts index ddc71476c1..6ff93d15e9 100644 --- a/src/vs/workbench/contrib/debug/common/debugUtils.ts +++ b/src/vs/workbench/contrib/debug/common/debugUtils.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { equalsIgnoreCase } from 'vs/base/common/strings'; -import { IConfig, IDebuggerContribution, IDebugService } from 'vs/workbench/contrib/debug/common/debug'; +import { IConfig, IDebuggerContribution, IDebugService, IDebugSession } from 'vs/workbench/contrib/debug/common/debug'; import { URI as uri } from 'vs/base/common/uri'; import { isAbsolute } from 'vs/base/common/path'; import { deepClone } from 'vs/base/common/objects'; @@ -42,6 +42,10 @@ export function formatPII(value: string, excludePII: boolean, args: { [key: stri }); } +export function isSessionAttach(session: IDebugSession): boolean { + return !session.parentSession && session.configuration.request === 'attach' && !isExtensionHostDebugging(session.configuration); +} + export function isExtensionHostDebugging(config: IConfig) { return config.type && equalsIgnoreCase(config.type === 'vslsShare' ? (config).adapterProxy.configuration.type : config.type, 'extensionhost'); } diff --git a/src/vs/workbench/contrib/debug/common/debugViewModel.ts b/src/vs/workbench/contrib/debug/common/debugViewModel.ts index 7b7c4317d3..cf696c3aeb 100644 --- a/src/vs/workbench/contrib/debug/common/debugViewModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugViewModel.ts @@ -6,7 +6,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { CONTEXT_EXPRESSION_SELECTED, IViewModel, IStackFrame, IDebugSession, IThread, IExpression, IFunctionBreakpoint, CONTEXT_BREAKPOINT_SELECTED, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { isExtensionHostDebugging } from 'vs/workbench/contrib/debug/common/debugUtils'; +import { isSessionAttach } from 'vs/workbench/contrib/debug/common/debugUtils'; export class ViewModel implements IViewModel { @@ -71,7 +71,7 @@ export class ViewModel implements IViewModel { this.stepBackSupportedContextKey.set(session ? !!session.capabilities.supportsStepBack : false); this.restartFrameSupportedContextKey.set(session ? !!session.capabilities.supportsRestartFrame : false); this.jumpToCursorSupported.set(session ? !!session.capabilities.supportsGotoTargetsRequest : false); - const attach = !!session && !session.parentSession && session.configuration.request === 'attach' && !isExtensionHostDebugging(session.configuration); + const attach = !!session && isSessionAttach(session); this.focusedSessionIsAttach.set(attach); if (shouldEmitForSession) { diff --git a/src/vs/workbench/contrib/debug/common/replModel.ts b/src/vs/workbench/contrib/debug/common/replModel.ts index 0200ca7645..6fe9a77264 100644 --- a/src/vs/workbench/contrib/debug/common/replModel.ts +++ b/src/vs/workbench/contrib/debug/common/replModel.ts @@ -6,15 +6,105 @@ import * as nls from 'vs/nls'; import severity from 'vs/base/common/severity'; import { IReplElement, IStackFrame, IExpression, IReplElementSource, IDebugSession } from 'vs/workbench/contrib/debug/common/debug'; -import { Expression, SimpleReplElement, RawObjectReplElement } from 'vs/workbench/contrib/debug/common/debugModel'; -import { isUndefinedOrNull, isObject } from 'vs/base/common/types'; +import { ExpressionContainer } from 'vs/workbench/contrib/debug/common/debugModel'; +import { isString, isUndefinedOrNull, isObject } from 'vs/base/common/types'; import { basenameOrAuthority } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { endsWith } from 'vs/base/common/strings'; +import { generateUuid } from 'vs/base/common/uuid'; const MAX_REPL_LENGTH = 10000; let topReplElementCounter = 0; +export class SimpleReplElement implements IReplElement { + constructor( + private id: string, + public value: string, + public severity: severity, + public sourceData?: IReplElementSource, + ) { } + + toString(): string { + return this.value; + } + + getId(): string { + return this.id; + } +} + +export class RawObjectReplElement implements IExpression { + + private static readonly MAX_CHILDREN = 1000; // upper bound of children per value + + constructor(private id: string, public name: string, public valueObj: any, public sourceData?: IReplElementSource, public annotation?: string) { } + + getId(): string { + return this.id; + } + + get value(): string { + if (this.valueObj === null) { + return 'null'; + } else if (Array.isArray(this.valueObj)) { + return `Array[${this.valueObj.length}]`; + } else if (isObject(this.valueObj)) { + return 'Object'; + } else if (isString(this.valueObj)) { + return `"${this.valueObj}"`; + } + + return String(this.valueObj) || ''; + } + + get hasChildren(): boolean { + return (Array.isArray(this.valueObj) && this.valueObj.length > 0) || (isObject(this.valueObj) && Object.getOwnPropertyNames(this.valueObj).length > 0); + } + + getChildren(): Promise { + let result: IExpression[] = []; + if (Array.isArray(this.valueObj)) { + result = (this.valueObj).slice(0, RawObjectReplElement.MAX_CHILDREN) + .map((v, index) => new RawObjectReplElement(`${this.id}:${index}`, String(index), v)); + } else if (isObject(this.valueObj)) { + result = Object.getOwnPropertyNames(this.valueObj).slice(0, RawObjectReplElement.MAX_CHILDREN) + .map((key, index) => new RawObjectReplElement(`${this.id}:${index}`, key, this.valueObj[key])); + } + + return Promise.resolve(result); + } + + toString(): string { + return `${this.name}\n${this.value}`; + } +} + +export class ReplEvaluationInput implements IReplElement { + private id: string; + + constructor(public value: string) { + this.id = generateUuid(); + } + + toString(): string { + return this.value; + } + + getId(): string { + return this.id; + } +} + +export class ReplEvaluationResult extends ExpressionContainer implements IReplElement { + constructor() { + super(undefined, undefined, 0, generateUuid()); + } + + toString(): string { + return `${this.value}`; + } +} + export class ReplModel { private replElements: IReplElement[] = []; @@ -24,10 +114,11 @@ export class ReplModel { return this.replElements; } - addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise { - const expression = new Expression(name); - this.addReplElement(expression); - return expression.evaluate(this.session, stackFrame, 'repl'); + async addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise { + this.addReplElement(new ReplEvaluationInput(name)); + const result = new ReplEvaluationResult(); + await result.evaluateExpression(name, this.session, stackFrame, 'repl'); + this.addReplElement(result); } appendToRepl(data: string | IExpression, sev: severity, source?: IReplElementSource): void { diff --git a/src/vs/workbench/contrib/debug/node/debugAdapter.ts b/src/vs/workbench/contrib/debug/node/debugAdapter.ts index 10f85acca6..f1aad47535 100644 --- a/src/vs/workbench/contrib/debug/node/debugAdapter.ts +++ b/src/vs/workbench/contrib/debug/node/debugAdapter.ts @@ -127,11 +127,8 @@ export class SocketDebugAdapter extends StreamDebugAdapter { }); } - stopSession(): Promise { - - // Cancel all sent promises on disconnect so debug trees are not left in a broken state #3666. - this.cancelPending(); - + async stopSession(): Promise { + await this.cancelPendingRequests(); if (this.socket) { this.socket.end(); this.socket = undefined; @@ -252,10 +249,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { } } - stopSession(): Promise { - - // Cancel all sent promises on disconnect so debug trees are not left in a broken state #3666. - this.cancelPending(); + async stopSession(): Promise { if (!this.serverProcess) { return Promise.resolve(undefined); @@ -264,6 +258,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { // when killing a process in windows its child // processes are *not* killed but become root // processes. Therefore we use TASKKILL.EXE + await this.cancelPendingRequests(); if (platform.isWindows) { return new Promise((c, e) => { const killer = cp.exec(`taskkill /F /T /PID ${this.serverProcess!.pid}`, function (err, stdout, stderr) { diff --git a/src/vs/workbench/contrib/debug/node/debugHelperService.ts b/src/vs/workbench/contrib/debug/node/debugHelperService.ts index c6e8844f5a..81e5e6f93e 100644 --- a/src/vs/workbench/contrib/debug/node/debugHelperService.ts +++ b/src/vs/workbench/contrib/debug/node/debugHelperService.ts @@ -12,7 +12,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class NodeDebugHelperService implements IDebugHelperService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( ) { diff --git a/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts b/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts index 7a72180075..ed174a03ed 100644 --- a/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts @@ -9,9 +9,21 @@ import * as dom from 'vs/base/browser/dom'; import { Expression, Variable, Scope, StackFrame, Thread } from 'vs/workbench/contrib/debug/common/debugModel'; import { MockSession } from 'vs/workbench/contrib/debug/test/common/mockDebug'; import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; +import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector'; +import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; +import { workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices'; const $ = dom.$; suite('Debug - Base Debug View', () => { + let linkDetector: LinkDetector; + + /** + * Instantiate services for use by the functions being tested. + */ + setup(() => { + const instantiationService: TestInstantiationService = workbenchInstantiationService(); + linkDetector = instantiationService.createInstance(LinkDetector); + }); test('replace whitespace', () => { assert.equal(replaceWhitespace('hey there'), 'hey there'); @@ -36,7 +48,7 @@ suite('Debug - Base Debug View', () => { expression.available = true; expression.value = '"string value"'; container = $('.container'); - renderExpressionValue(expression, container, { colorize: true }); + renderExpressionValue(expression, container, { colorize: true, linkDetector }); assert.equal(container.className, 'value string'); assert.equal(container.textContent, '"string value"'); @@ -48,8 +60,14 @@ suite('Debug - Base Debug View', () => { expression.value = 'this is a long string'; container = $('.container'); - renderExpressionValue(expression, container, { colorize: true, maxValueLength: 4 }); + renderExpressionValue(expression, container, { colorize: true, maxValueLength: 4, linkDetector }); assert.equal(container.textContent, 'this...'); + + expression.value = process.platform === 'win32' ? 'C:\\foo.js:5' : '/foo.js:5'; + container = $('.container'); + renderExpressionValue(expression, container, { colorize: true, linkDetector }); + assert.ok(container.querySelector('a')); + assert.equal(container.querySelector('a')!.textContent, expression.value); }); test.skip('render variable', () => { // {{SQL CARBON EDIT}} skip test @@ -58,7 +76,7 @@ suite('Debug - Base Debug View', () => { const stackFrame = new StackFrame(thread, 1, null!, 'app.js', 'normal', { startLineNumber: 1, startColumn: 1, endLineNumber: undefined!, endColumn: undefined! }, 0); const scope = new Scope(stackFrame, 1, 'local', 1, false, 10, 10); - let variable = new Variable(session, scope, 2, 'foo', 'bar.foo', undefined!, 0, 0, {}, 'string'); + let variable = new Variable(session, 1, scope, 2, 'foo', 'bar.foo', undefined!, 0, 0, {}, 'string'); let expression = $('.'); let name = $('.'); let value = $('.'); @@ -73,16 +91,24 @@ suite('Debug - Base Debug View', () => { expression = $('.'); name = $('.'); value = $('.'); - renderVariable(variable, { expression, name, value, label }, false, []); + renderVariable(variable, { expression, name, value, label }, false, [], linkDetector); assert.equal(value.textContent, 'hey'); assert.equal(label.element.textContent, 'foo:'); assert.equal(label.element.title, 'string'); - variable = new Variable(session, scope, 2, 'console', 'console', '5', 0, 0, { kind: 'virtual' }); + variable.value = process.platform === 'win32' ? 'C:\\foo.js:5' : '/foo.js:5'; expression = $('.'); name = $('.'); value = $('.'); - renderVariable(variable, { expression, name, value, label }, false, []); + renderVariable(variable, { expression, name, value, label }, false, [], linkDetector); + assert.ok(value.querySelector('a')); + assert.equal(value.querySelector('a')!.textContent, variable.value); + + variable = new Variable(session, 1, scope, 2, 'console', 'console', '5', 0, 0, { kind: 'virtual' }); + expression = $('.'); + name = $('.'); + value = $('.'); + renderVariable(variable, { expression, name, value, label }, false, [], linkDetector); assert.equal(name.className, 'virtual'); assert.equal(label.element.textContent, 'console:'); assert.equal(label.element.title, 'console'); 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 a7d1ec2418..09338dc504 100644 --- a/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts @@ -6,12 +6,12 @@ import * as assert from 'assert'; import { URI as uri } from 'vs/base/common/uri'; import severity from 'vs/base/common/severity'; -import { SimpleReplElement, DebugModel, Expression, RawObjectReplElement, StackFrame, Thread } from 'vs/workbench/contrib/debug/common/debugModel'; +import { DebugModel, Expression, StackFrame, Thread } from 'vs/workbench/contrib/debug/common/debugModel'; import * as sinon from 'sinon'; import { MockRawSession } from 'vs/workbench/contrib/debug/test/common/mockDebug'; import { Source } from 'vs/workbench/contrib/debug/common/debugSource'; import { DebugSession } from 'vs/workbench/contrib/debug/browser/debugSession'; -import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel'; +import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplModel } from 'vs/workbench/contrib/debug/common/replModel'; import { IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug'; import { NullOpenerService } from 'vs/platform/opener/common/opener'; @@ -24,7 +24,7 @@ suite('Debug - Model', () => { let rawSession: MockRawSession; setup(() => { - model = new DebugModel([], true, [], [], [], [], { isDirty: (e: any) => false }); + model = new DebugModel([], [], [], [], [], { isDirty: (e: any) => false }); rawSession = new MockRawSession(); }); @@ -348,9 +348,7 @@ suite('Debug - Model', () => { assert.equal(replModel.getReplElements().length, 3); replModel.getReplElements().forEach(re => { - assert.equal((re).available, false); - assert.equal((re).name, 'myVariable'); - assert.equal((re).reference, 0); + assert.equal((re).value, 'myVariable'); }); replModel.removeReplExpressions(); diff --git a/src/vs/workbench/contrib/debug/test/common/mockDebug.ts b/src/vs/workbench/contrib/debug/test/common/mockDebug.ts index d592f33eec..d01a67855b 100644 --- a/src/vs/workbench/contrib/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/contrib/debug/test/common/mockDebug.ts @@ -14,7 +14,7 @@ import Severity from 'vs/base/common/severity'; export class MockDebugService implements IDebugService { - public _serviceBrand: any; + public _serviceBrand: undefined; public get state(): State { throw new Error('not implemented'); @@ -180,6 +180,10 @@ export class MockSession implements IDebugSession { return 'mockname'; } + setName(name: string): void { + throw new Error('not implemented'); + } + getSourceForUri(modelUri: uri): Source { throw new Error('not implemented'); } @@ -204,6 +208,10 @@ export class MockSession implements IDebugSession { throw new Error('not implemented'); } + get onDidChangeName(): Event { + throw new Error('not implemented'); + } + setConfiguration(configuration: { resolved: IConfig, unresolved: IConfig }) { } getAllThreads(): IThread[] { @@ -256,7 +264,7 @@ export class MockSession implements IDebugSession { scopes(frameId: number): Promise { throw new Error('Method not implemented.'); } - variables(variablesReference: number, filter: 'indexed' | 'named', start: number, count: number): Promise { + variables(variablesReference: number, threadId: number | undefined, filter: 'indexed' | 'named', start: number, count: number): Promise { throw new Error('Method not implemented.'); } evaluate(expression: string, frameId: number, context?: string): Promise { diff --git a/src/vs/workbench/contrib/experiments/common/experimentService.ts b/src/vs/workbench/contrib/experiments/common/experimentService.ts index 6d3cca0245..4ef7728f75 100644 --- a/src/vs/workbench/contrib/experiments/common/experimentService.ts +++ b/src/vs/workbench/contrib/experiments/common/experimentService.ts @@ -63,7 +63,7 @@ export interface IExperiment { } export interface IExperimentService { - _serviceBrand: any; + _serviceBrand: undefined; getExperimentById(id: string): Promise; getExperimentsByType(type: ExperimentActionType): Promise; getCuratedExtensionsList(curatedExtensionsKey: string): Promise; @@ -108,7 +108,7 @@ interface IRawExperiment { } export class ExperimentService extends Disposable implements IExperimentService { - _serviceBrand: any; + _serviceBrand: undefined; private _experiments: IExperiment[] = []; private _loadExperimentsPromise: Promise; private _curatedMapping = Object.create(null); @@ -169,7 +169,7 @@ export class ExperimentService extends Disposable implements IExperimentService this.storageService.store(storageKey, JSON.stringify(experimentState), StorageScope.GLOBAL); } - protected getExperiments(): Promise { + protected getExperiments(): Promise { if (!this.productService.experimentsUrl || this.configurationService.getValue('workbench.enableExperiments') === false) { return Promise.resolve([]); } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index 365a0cead0..c969eb50b8 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -301,7 +301,7 @@ export class ExtensionEditor extends BaseEditor { return disposables; } - async setInput(input: ExtensionsInput, options: EditorOptions, token: CancellationToken): Promise { + async setInput(input: ExtensionsInput, options: EditorOptions | undefined, token: CancellationToken): Promise { if (this.template) { await this.updateTemplate(input, this.template); } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts b/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts index 5ef2a9831d..be089c2858 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts @@ -75,7 +75,7 @@ function caseInsensitiveGet(obj: { [key: string]: T }, key: string): T | unde export class ExtensionTipsService extends Disposable implements IExtensionTipsService { - _serviceBrand: any; + _serviceBrand: undefined; private _fileBasedRecommendations: { [id: string]: { recommendedTime: number, sources: ExtensionRecommendationSource[] }; } = Object.create(null); private _recommendations: string[] = []; // {{SQL CARBON EDIT}} @@ -651,16 +651,18 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe } }); - forEach(this.productService.extensionImportantTips, entry => { - let { key: id, value } = entry; - const { pattern } = value; - let ids = this._availableRecommendations[pattern]; - if (!ids) { - this._availableRecommendations[pattern] = [id.toLowerCase()]; - } else { - ids.push(id.toLowerCase()); - } - }); + if (this.productService.extensionImportantTips) { + forEach(this.productService.extensionImportantTips, entry => { + let { key: id, value } = entry; + const { pattern } = value; + let ids = this._availableRecommendations[pattern]; + if (!ids) { + this._availableRecommendations[pattern] = [id.toLowerCase()]; + } else { + ids.push(id.toLowerCase()); + } + }); + } const allRecommendations: string[] = flatten((Object.keys(this._availableRecommendations).map(key => this._availableRecommendations[key]))); @@ -713,7 +715,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe let { key: pattern, value: ids } = entry; if (match(pattern, model.uri.toString())) { for (let id of ids) { - if (caseInsensitiveGet(this.productService.extensionImportantTips, id)) { + if (this.productService.extensionImportantTips && caseInsensitiveGet(this.productService.extensionImportantTips, id)) { recommendationsToSuggest.push(id); } const filedBasedRecommendation = this._fileBasedRecommendations[id.toLowerCase()] || { recommendedTime: now, sources: [] }; @@ -767,7 +769,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe } const id = recommendationsToSuggest[0]; - const entry = caseInsensitiveGet(this.productService.extensionImportantTips, id); + const entry = this.productService.extensionImportantTips ? caseInsensitiveGet(this.productService.extensionImportantTips, id) : undefined; if (!entry) { return false; } @@ -996,7 +998,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe * If user has any of the tools listed in this.productService.exeBasedExtensionTips, fetch corresponding recommendations */ private async fetchExecutableRecommendations(important: boolean): Promise { - if (isWeb) { + if (isWeb || !this.productService.exeBasedExtensionTips) { return; } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index d138db2745..3f50ed7d1c 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -1629,7 +1629,7 @@ export class ShowRecommendedExtensionsAction extends Action { return this.viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => { - viewlet.search('@recommended '); + viewlet.search('@recommended ', true); viewlet.focus(); }); } @@ -3121,7 +3121,7 @@ export class InstallLocalExtensionsInRemoteAction extends Action { get label(): string { if (this.extensionManagementServerService.remoteExtensionManagementServer) { - return localize('select and install local extensions', "Install Local Extensions in {0}...", this.extensionManagementServerService.remoteExtensionManagementServer.label); + return localize('select and install local extensions', "Install Local Extensions in '{0}'...", this.extensionManagementServerService.remoteExtensionManagementServer.label); } return ''; } @@ -3166,7 +3166,7 @@ export class InstallLocalExtensionsInRemoteAction extends Action { const localExtensionsToInstall = await this.queryExtensionsToInstall(); quickPick.busy = false; if (localExtensionsToInstall.length) { - quickPick.title = localize('install local extensions title', "Install Local Extensions in {0}", this.extensionManagementServerService.remoteExtensionManagementServer!.label); + quickPick.title = localize('install local extensions title', "Install Local Extensions in '{0}'", this.extensionManagementServerService.remoteExtensionManagementServer!.label); quickPick.placeholder = localize('select extensions to install', "Select extensions to install"); quickPick.canSelectMany = true; localExtensionsToInstall.sort((e1, e2) => e1.displayName.localeCompare(e2.displayName)); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts index b9f50fa295..203c09d4a3 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts @@ -198,6 +198,7 @@ export class ExtensionsTree extends WorkbenchAsyncDataTree('nonEmptyWorkspace', false); const DefaultViewsContext = new RawContextKey('defaultExtensionViews', true); const SearchMarketplaceExtensionsContext = new RawContextKey('searchMarketplaceExtensions', false); @@ -494,12 +489,13 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio return this.secondaryActions; } - search(value: string): void { + search(value: string, refresh: boolean = false): void { if (this.searchBox) { - const event = new Event('input', { bubbles: true }) as SearchInputEvent; - event.immediate = true; - - this.searchBox.setValue(value); + if (this.searchBox.getValue() !== value) { + this.searchBox.setValue(value); + } else if (refresh) { + this.doSearch(); + } } } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts index 5b9730d7ea..a649f6b095 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts @@ -125,12 +125,12 @@ export class ExtensionsListView extends ViewletPanel { const delegate = new Delegate(); const extensionsViewState = new ExtensionsViewState(); const renderer = this.instantiationService.createInstance(Renderer, extensionsViewState); - this.list = this.instantiationService.createInstance(WorkbenchPagedList, extensionsList, delegate, [renderer], { + this.list = this.instantiationService.createInstance(WorkbenchPagedList, 'Extensions', extensionsList, delegate, [renderer], { ariaLabel: localize('extensions', "Extensions"), multipleSelectionSupport: false, setRowLineHeight: false, horizontalScrolling: false - }) as WorkbenchPagedList; + }); this._register(this.list.onContextMenu(e => this.onContextMenu(e), this)); this._register(this.list.onFocusChange(e => extensionsViewState.onFocusChange(coalesce(e.elements)), this)); this._register(this.list); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts index 8d85f13468..8b41f72055 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts @@ -170,8 +170,8 @@ export class TooltipWidget extends ExtensionWidget { if (!this.extension) { return ''; } - if (this.tooltipAction.tooltip) { - return this.tooltipAction.tooltip; + if (this.tooltipAction.label) { + return this.tooltipAction.label; } return this.recommendationWidget.tooltip; } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index 5386319541..20b4cb3fd7 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -489,7 +489,7 @@ class Extensions extends Disposable { export class ExtensionsWorkbenchService extends Disposable implements IExtensionsWorkbenchService, IURLHandler { private static readonly SyncPeriod = 1000 * 60 * 60 * 12; // 12 hours - _serviceBrand: any; + _serviceBrand: undefined; private readonly localExtensions: Extensions | null = null; private readonly remoteExtensions: Extensions | null = null; diff --git a/src/vs/workbench/contrib/extensions/browser/media/clear-inverse.svg b/src/vs/workbench/contrib/extensions/browser/media/clear-inverse.svg deleted file mode 100644 index 85e7ec4bda..0000000000 --- a/src/vs/workbench/contrib/extensions/browser/media/clear-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/extensions/common/extensions.ts b/src/vs/workbench/contrib/extensions/common/extensions.ts index 64c389a232..6ad0ec043b 100644 --- a/src/vs/workbench/contrib/extensions/common/extensions.ts +++ b/src/vs/workbench/contrib/extensions/common/extensions.ts @@ -23,7 +23,7 @@ export const VIEW_CONTAINER: ViewContainer = Registry.as(SERVICE_ID); export interface IExtensionsWorkbenchService { - _serviceBrand: any; + _serviceBrand: undefined; onChange: Event; local: IExtension[]; installed: IExtension[]; diff --git a/src/vs/workbench/contrib/extensions/common/extensionsFileTemplate.ts b/src/vs/workbench/contrib/extensions/common/extensionsFileTemplate.ts index c3f5c3ac8c..3b7a598268 100644 --- a/src/vs/workbench/contrib/extensions/common/extensionsFileTemplate.ts +++ b/src/vs/workbench/contrib/extensions/common/extensionsFileTemplate.ts @@ -11,6 +11,7 @@ export const ExtensionsConfigurationSchemaId = 'vscode://schemas/extensions'; export const ExtensionsConfigurationSchema: IJSONSchema = { id: ExtensionsConfigurationSchemaId, allowComments: true, + allowsTrailingCommas: true, type: 'object', title: localize('app.extensions.json.title', "Extensions"), additionalProperties: false, @@ -50,4 +51,4 @@ export const ExtensionsConfigurationInitialContent: string = [ '\t\t', '\t]', '}' -].join('\n'); \ No newline at end of file +].join('\n'); diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts index ac6e44411d..fb8f7304a4 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts @@ -23,7 +23,7 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; export class ExtensionHostProfileService extends Disposable implements IExtensionHostProfileService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _onDidChangeState: Emitter = this._register(new Emitter()); public readonly onDidChangeState: Event = this._onDidChangeState.event; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts index 6700e78f69..49ce8cc194 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts @@ -21,6 +21,7 @@ import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/electron import { URI } from 'vs/base/common/uri'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ExtensionsAutoProfiler } from 'vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; // Singletons registerSingleton(IExtensionHostProfileService, ExtensionHostProfileService, true); @@ -85,8 +86,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: DebugExtensionHostAction.ID, title: DebugExtensionHostAction.LABEL, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/start-dark.svg`)), - light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/start-light.svg`)), + dark: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/start-dark.svg`)), + light: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/start-light.svg`)), } }, group: 'navigation', @@ -98,8 +99,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: StartExtensionHostProfileAction.ID, title: StartExtensionHostProfileAction.LABEL, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/profile-start-dark.svg`)), - light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/profile-start-light.svg`)), + dark: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/profile-start-dark.svg`)), + light: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/profile-start-light.svg`)), } }, group: 'navigation', @@ -111,8 +112,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: StopExtensionHostProfileAction.ID, title: StopExtensionHostProfileAction.LABEL, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/profile-stop-dark.svg`)), - light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/profile-stop-light.svg`)), + dark: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/profile-stop-dark.svg`)), + light: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/profile-stop-light.svg`)), } }, group: 'navigation', @@ -124,8 +125,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: SaveExtensionHostProfileAction.ID, title: SaveExtensionHostProfileAction.LABEL, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/save-dark.svg`)), - light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/save-light.svg`)), + dark: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/save-dark.svg`)), + light: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/save-light.svg`)), }, precondition: CONTEXT_EXTENSION_HOST_PROFILE_RECORDED }, diff --git a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts index f3e4e5d74b..2f7a265293 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts @@ -59,7 +59,7 @@ export enum ProfileSessionState { } export interface IExtensionHostProfileService { - _serviceBrand: any; + _serviceBrand: undefined; readonly onDidChangeState: Event; readonly onDidChangeLastProfile: Event; @@ -404,7 +404,9 @@ export class RuntimeExtensionsEditor extends BaseEditor { } }; - this._list = this._instantiationService.createInstance(WorkbenchList, parent, delegate, [renderer], { + this._list = this._instantiationService.createInstance(WorkbenchList, + 'RuntimeExtensions', + parent, delegate, [renderer], { multipleSelectionSupport: false, setRowLineHeight: false, horizontalScrolling: false @@ -502,13 +504,11 @@ export class ReportExtensionIssueAction extends Action { status?: IExtensionsStatus; unresponsiveProfile?: IExtensionHostProfile }): string { - - let baseUrl = extension.marketplaceInfo && extension.marketplaceInfo.type === ExtensionType.User && extension.description.repository ? extension.description.repository.url : undefined; if (!!baseUrl) { baseUrl = `${baseUrl.indexOf('.git') !== -1 ? baseUrl.substr(0, baseUrl.length - 4) : baseUrl}/issues/new/`; } else { - baseUrl = product.reportIssueUrl; + baseUrl = product.reportIssueUrl!; } let reason = 'Bug'; 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 73ab83dfd3..b002e5c3f5 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 @@ -2245,7 +2245,7 @@ suite('ExtensionsActions Test', () => { extensionManagementService: remoteExtensionManagementService || createExtensionManagementService() }; return { - _serviceBrand: {}, + _serviceBrand: undefined, localExtensionManagementServer: null, remoteExtensionManagementServer, getExtensionManagementServer: (location: URI) => { @@ -2269,7 +2269,7 @@ suite('ExtensionsActions Test', () => { extensionManagementService: remoteExtensionManagementService || createExtensionManagementService() }; return { - _serviceBrand: {}, + _serviceBrand: undefined, localExtensionManagementServer, remoteExtensionManagementServer, getExtensionManagementServer: (location: URI) => { diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts index 7386f8cffe..36bd1e0ad1 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts @@ -65,17 +65,17 @@ const mockExtensionGallery: IGalleryExtension[] = [ rating: 4, ratingCount: 100 }, { - dependencies: ['pub.1'], - }, { - manifest: { uri: 'uri:manifest', fallbackUri: 'fallback:manifest' }, - readme: { uri: 'uri:readme', fallbackUri: 'fallback:readme' }, - changelog: { uri: 'uri:changelog', fallbackUri: 'fallback:changlog' }, - download: { uri: 'uri:download', fallbackUri: 'fallback:download' }, - icon: { uri: 'uri:icon', fallbackUri: 'fallback:icon' }, - license: { uri: 'uri:license', fallbackUri: 'fallback:license' }, - repository: { uri: 'uri:repository', fallbackUri: 'fallback:repository' }, - coreTranslations: [] - }), + dependencies: ['pub.1'], + }, { + manifest: { uri: 'uri:manifest', fallbackUri: 'fallback:manifest' }, + readme: { uri: 'uri:readme', fallbackUri: 'fallback:readme' }, + changelog: { uri: 'uri:changelog', fallbackUri: 'fallback:changlog' }, + download: { uri: 'uri:download', fallbackUri: 'fallback:download' }, + icon: { uri: 'uri:icon', fallbackUri: 'fallback:icon' }, + license: { uri: 'uri:license', fallbackUri: 'fallback:license' }, + repository: { uri: 'uri:repository', fallbackUri: 'fallback:repository' }, + coreTranslations: [] + }), aGalleryExtension('MockExtension2', { displayName: 'Mock Extension 2', version: '1.5', @@ -87,17 +87,17 @@ const mockExtensionGallery: IGalleryExtension[] = [ rating: 4, ratingCount: 100 }, { - dependencies: ['pub.1', 'pub.2'], - }, { - manifest: { uri: 'uri:manifest', fallbackUri: 'fallback:manifest' }, - readme: { uri: 'uri:readme', fallbackUri: 'fallback:readme' }, - changelog: { uri: 'uri:changelog', fallbackUri: 'fallback:changlog' }, - download: { uri: 'uri:download', fallbackUri: 'fallback:download' }, - icon: { uri: 'uri:icon', fallbackUri: 'fallback:icon' }, - license: { uri: 'uri:license', fallbackUri: 'fallback:license' }, - repository: { uri: 'uri:repository', fallbackUri: 'fallback:repository' }, - coreTranslations: [] - }) + dependencies: ['pub.1', 'pub.2'], + }, { + manifest: { uri: 'uri:manifest', fallbackUri: 'fallback:manifest' }, + readme: { uri: 'uri:readme', fallbackUri: 'fallback:readme' }, + changelog: { uri: 'uri:changelog', fallbackUri: 'fallback:changlog' }, + download: { uri: 'uri:download', fallbackUri: 'fallback:download' }, + icon: { uri: 'uri:icon', fallbackUri: 'fallback:icon' }, + license: { uri: 'uri:license', fallbackUri: 'fallback:license' }, + repository: { uri: 'uri:repository', fallbackUri: 'fallback:repository' }, + coreTranslations: [] + }) ]; const mockExtensionLocal = [ @@ -235,7 +235,7 @@ suite.skip('ExtensionsTipsService Test', () => { // {{SQL CARBON EDIT}} skip sui }); setup(() => { - instantiationService.stub(IEnvironmentService, >{ extensionDevelopmentPath: false }); + instantiationService.stub(IEnvironmentService, >{}); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', []); instantiationService.stub(IExtensionGalleryService, 'isEnabled', true); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(...mockExtensionGallery)); diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts index 056b33497c..abd8a2dd40 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts @@ -121,17 +121,17 @@ suite('ExtensionsWorkbenchServiceTest', () => { rating: 4, ratingCount: 100 }, { - dependencies: ['pub.1', 'pub.2'], - }, { - manifest: { uri: 'uri:manifest', fallbackUri: 'fallback:manifest' }, - readme: { uri: 'uri:readme', fallbackUri: 'fallback:readme' }, - changelog: { uri: 'uri:changelog', fallbackUri: 'fallback:changlog' }, - download: { uri: 'uri:download', fallbackUri: 'fallback:download' }, - icon: { uri: 'uri:icon', fallbackUri: 'fallback:icon' }, - license: { uri: 'uri:license', fallbackUri: 'fallback:license' }, - repository: { uri: 'uri:repository', fallbackUri: 'fallback:repository' }, - coreTranslations: [] - }); + dependencies: ['pub.1', 'pub.2'], + }, { + manifest: { uri: 'uri:manifest', fallbackUri: 'fallback:manifest' }, + readme: { uri: 'uri:readme', fallbackUri: 'fallback:readme' }, + changelog: { uri: 'uri:changelog', fallbackUri: 'fallback:changlog' }, + download: { uri: 'uri:download', fallbackUri: 'fallback:download' }, + icon: { uri: 'uri:icon', fallbackUri: 'fallback:icon' }, + license: { uri: 'uri:license', fallbackUri: 'fallback:license' }, + repository: { uri: 'uri:repository', fallbackUri: 'fallback:repository' }, + coreTranslations: [] + }); testObject = await aWorkbenchService(); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(expected)); @@ -176,21 +176,21 @@ suite('ExtensionsWorkbenchServiceTest', () => { icon: 'localIcon1', extensionDependencies: ['pub.1', 'pub.2'], }, { - type: ExtensionType.User, - readmeUrl: 'localReadmeUrl1', - changelogUrl: 'localChangelogUrl1', - location: URI.file('localPath1') - }); + type: ExtensionType.User, + readmeUrl: 'localReadmeUrl1', + changelogUrl: 'localChangelogUrl1', + location: URI.file('localPath1') + }); const expected2 = aLocalExtension('local2', { publisher: 'localPublisher2', version: '1.2.0', displayName: 'localDisplayName2', description: 'localDescription2', }, { - type: ExtensionType.System, - readmeUrl: 'localReadmeUrl2', - changelogUrl: 'localChangelogUrl2', - }); + type: ExtensionType.System, + readmeUrl: 'localReadmeUrl2', + changelogUrl: 'localChangelogUrl2', + }); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [expected1, expected2]); testObject = await aWorkbenchService(); @@ -244,21 +244,21 @@ suite('ExtensionsWorkbenchServiceTest', () => { icon: 'localIcon1', extensionDependencies: ['pub.1', 'pub.2'], }, { - type: ExtensionType.User, - readmeUrl: 'localReadmeUrl1', - changelogUrl: 'localChangelogUrl1', - location: URI.file('localPath1') - }); + type: ExtensionType.User, + readmeUrl: 'localReadmeUrl1', + changelogUrl: 'localChangelogUrl1', + location: URI.file('localPath1') + }); const local2 = aLocalExtension('local2', { publisher: 'localPublisher2', version: '1.2.0', displayName: 'localDisplayName2', description: 'localDescription2', }, { - type: ExtensionType.System, - readmeUrl: 'localReadmeUrl2', - changelogUrl: 'localChangelogUrl2', - }); + type: ExtensionType.System, + readmeUrl: 'localReadmeUrl2', + changelogUrl: 'localChangelogUrl2', + }); const gallery1 = aGalleryExtension(local1.manifest.name, { identifier: local1.identifier, displayName: 'expectedDisplayName', @@ -271,17 +271,17 @@ suite('ExtensionsWorkbenchServiceTest', () => { rating: 4, ratingCount: 100 }, { - dependencies: ['pub.1'], - }, { - manifest: { uri: 'uri:manifest', fallbackUri: 'fallback:manifest' }, - readme: { uri: 'uri:readme', fallbackUri: 'fallback:readme' }, - changelog: { uri: 'uri:changelog', fallbackUri: 'fallback:changlog' }, - download: { uri: 'uri:download', fallbackUri: 'fallback:download' }, - icon: { uri: 'uri:icon', fallbackUri: 'fallback:icon' }, - license: { uri: 'uri:license', fallbackUri: 'fallback:license' }, - repository: { uri: 'uri:repository', fallbackUri: 'fallback:repository' }, - coreTranslations: [] - }); + dependencies: ['pub.1'], + }, { + manifest: { uri: 'uri:manifest', fallbackUri: 'fallback:manifest' }, + readme: { uri: 'uri:readme', fallbackUri: 'fallback:readme' }, + changelog: { uri: 'uri:changelog', fallbackUri: 'fallback:changlog' }, + download: { uri: 'uri:download', fallbackUri: 'fallback:download' }, + icon: { uri: 'uri:icon', fallbackUri: 'fallback:icon' }, + license: { uri: 'uri:license', fallbackUri: 'fallback:license' }, + repository: { uri: 'uri:repository', fallbackUri: 'fallback:repository' }, + coreTranslations: [] + }); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local1, local2]); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery1)); testObject = await aWorkbenchService(); diff --git a/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts index 471860e423..af4cb39bbd 100644 --- a/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts +++ b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts @@ -10,7 +10,8 @@ import { URI } from 'vs/base/common/uri'; import { IExternalTerminalConfiguration, IExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/common/externalTerminal'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; -import { ITerminalService as IIntegratedTerminalService, KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED } from 'vs/workbench/contrib/terminal/common/terminal'; +import { KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService as IIntegratedTerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { ResourceContextKey } from 'vs/workbench/common/resources'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; diff --git a/src/vs/workbench/contrib/externalTerminal/common/externalTerminal.ts b/src/vs/workbench/contrib/externalTerminal/common/externalTerminal.ts index 3d33adc4d8..7428a4187b 100644 --- a/src/vs/workbench/contrib/externalTerminal/common/externalTerminal.ts +++ b/src/vs/workbench/contrib/externalTerminal/common/externalTerminal.ts @@ -14,7 +14,7 @@ export interface IExternalTerminalSettings { } export interface IExternalTerminalService { - _serviceBrand: any; + _serviceBrand: undefined; openTerminal(path: string): void; runInTerminal(title: string, cwd: string, args: string[], env: { [key: string]: string | null; }, settings: IExternalTerminalSettings): Promise; } diff --git a/src/vs/workbench/contrib/externalTerminal/node/externalTerminalService.ts b/src/vs/workbench/contrib/externalTerminal/node/externalTerminalService.ts index ca14ca1513..ae15fee962 100644 --- a/src/vs/workbench/contrib/externalTerminal/node/externalTerminalService.ts +++ b/src/vs/workbench/contrib/externalTerminal/node/externalTerminalService.ts @@ -23,7 +23,7 @@ const TERMINAL_TITLE = nls.localize('console.title', "VS Code Console"); export const DEFAULT_TERMINAL_OSX = 'Terminal.app'; export class WindowsExternalTerminalService implements IExternalTerminalService { - public _serviceBrand: any; + public _serviceBrand: undefined; private static readonly CMD = 'cmd.exe'; @@ -118,7 +118,7 @@ export class WindowsExternalTerminalService implements IExternalTerminalService } export class MacExternalTerminalService implements IExternalTerminalService { - public _serviceBrand: any; + public _serviceBrand: undefined; private static readonly OSASCRIPT = '/usr/bin/osascript'; // osascript is the AppleScript interpreter on OS X @@ -214,7 +214,7 @@ export class MacExternalTerminalService implements IExternalTerminalService { } export class LinuxExternalTerminalService implements IExternalTerminalService { - public _serviceBrand: any; + public _serviceBrand: undefined; private static readonly WAIT_MESSAGE = nls.localize('press.any.key', "Press any key to continue..."); @@ -305,7 +305,7 @@ export class LinuxExternalTerminalService implements IExternalTerminalService { if (!LinuxExternalTerminalService._DEFAULT_TERMINAL_LINUX_READY) { LinuxExternalTerminalService._DEFAULT_TERMINAL_LINUX_READY = new Promise(c => { if (env.isLinux) { - Promise.all([pfs.exists('/etc/debian_version'), process.lazyEnv || Promise.resolve(undefined)]).then(([isDebian]) => { + Promise.all([pfs.exists('/etc/debian_version'), Promise.resolve(process.lazyEnv) || Promise.resolve(undefined)]).then(([isDebian]) => { if (isDebian) { c('x-terminal-emulator'); } else if (process.env.DESKTOP_SESSION === 'gnome' || process.env.DESKTOP_SESSION === 'gnome-classic') { diff --git a/src/vs/workbench/contrib/feedback/browser/media/smiley.svg b/src/vs/workbench/contrib/feedback/browser/media/smiley.svg deleted file mode 100644 index 6bc9527890..0000000000 --- a/src/vs/workbench/contrib/feedback/browser/media/smiley.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts index 0e7eaa23ce..1bea6cf7ba 100644 --- a/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts @@ -49,7 +49,7 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor { ); } - private async openInternal(input: EditorInput, options: EditorOptions): Promise { + private async openInternal(input: EditorInput, options: EditorOptions | undefined): Promise { if (input instanceof FileEditorInput) { input.setForceOpenAsText(); @@ -57,7 +57,7 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor { } } - getTitle(): string | null { + getTitle(): string | undefined { return this.input ? this.input.getName() : nls.localize('binaryFileEditor', "Binary File Viewer"); } } diff --git a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts index d18a8c2e3b..d0fee65886 100644 --- a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { toErrorMessage } from 'vs/base/common/errorMessage'; -import * as types from 'vs/base/common/types'; +import { isFunction } from 'vs/base/common/types'; import { isValidBasename } from 'vs/base/common/extpath'; import { basename } from 'vs/base/common/resources'; import { Action } from 'vs/base/common/actions'; @@ -32,7 +32,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; import { MutableDisposable } from 'vs/base/common/lifecycle'; -import { EditorActivation } from 'vs/platform/editor/common/editor'; +import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor'; /** * An implementation of editor for file system resources. @@ -90,11 +90,11 @@ export class TextFileEditor extends BaseTextEditor { return this.input ? this.input.getName() : nls.localize('textFileEditor', "Text File Editor"); } - get input(): FileEditorInput { + get input(): FileEditorInput | undefined { return this._input as FileEditorInput; } - setEditorVisible(visible: boolean, group: IEditorGroup): void { + setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void { super.setEditorVisible(visible, group); // React to editors closing to preserve or clear view state. This needs to happen @@ -118,14 +118,14 @@ export class TextFileEditor extends BaseTextEditor { } } - setOptions(options: EditorOptions): void { - const textOptions = options; - if (textOptions && types.isFunction(textOptions.apply)) { + setOptions(options: EditorOptions | undefined): void { + const textOptions = options as TextEditorOptions; + if (textOptions && isFunction(textOptions.apply)) { textOptions.apply(this.getControl(), ScrollType.Smooth); } } - async setInput(input: FileEditorInput, options: EditorOptions, token: CancellationToken): Promise { + async setInput(input: FileEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { // Update/clear view settings if input changes this.doSaveOrClearTextEditorViewState(this.input); @@ -154,13 +154,13 @@ export class TextFileEditor extends BaseTextEditor { textEditor.setModel(textFileModel.textEditorModel); // Always restore View State if any associated - const editorViewState = this.loadTextEditorViewState(this.input.getResource()); + const editorViewState = this.loadTextEditorViewState(input.getResource()); if (editorViewState) { textEditor.restoreViewState(editorViewState); } // TextOptions (avoiding instanceof here for a reason, do not change!) - if (options && types.isFunction((options).apply)) { + if (options && isFunction((options).apply)) { (options).apply(textEditor, ScrollType.Immediate); } @@ -224,14 +224,19 @@ export class TextFileEditor extends BaseTextEditor { } } - private openAsBinary(input: FileEditorInput, options: EditorOptions): void { + private openAsBinary(input: FileEditorInput, options: EditorOptions | undefined): void { input.setForceOpenAsBinary(); // Make sure to not steal away the currently active group // because we are triggering another openEditor() call // and do not control the initial intent that resulted // in us now opening as binary. - options.overwrite({ activation: EditorActivation.PRESERVE }); + const preservingOptions: IEditorOptions = { activation: EditorActivation.PRESERVE }; + if (options) { + options.overwrite(preservingOptions); + } else { + options = EditorOptions.create(preservingOptions); + } this.editorService.openEditor(input, options, this.group); } @@ -286,7 +291,7 @@ export class TextFileEditor extends BaseTextEditor { super.saveState(); } - private doSaveOrClearTextEditorViewState(input: FileEditorInput): void { + private doSaveOrClearTextEditorViewState(input: FileEditorInput | undefined): void { if (!input) { return; // ensure we have an input to handle view state for } diff --git a/src/vs/workbench/contrib/files/browser/explorerViewlet.ts b/src/vs/workbench/contrib/files/browser/explorerViewlet.ts index f1c38ef8b7..dce2a76c68 100644 --- a/src/vs/workbench/contrib/files/browser/explorerViewlet.ts +++ b/src/vs/workbench/contrib/files/browser/explorerViewlet.ts @@ -121,7 +121,7 @@ export class ExplorerViewletViewsContribution extends Disposable implements IWor name: EmptyView.NAME, ctorDescriptor: { ctor: EmptyView }, order: 1, - canToggleVisibility: false + canToggleVisibility: true, }; } diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 4944b2e498..2a038c53ac 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -15,7 +15,7 @@ import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/c import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { isWindows, isMacintosh, isWeb } from 'vs/base/common/platform'; -import { FilesExplorerFocusCondition, ExplorerRootContext, ExplorerFolderContext, ExplorerResourceNotReadonlyContext, ExplorerResourceCut, IExplorerService, ExplorerResourceMoveableToTrash } from 'vs/workbench/contrib/files/common/files'; +import { FilesExplorerFocusCondition, ExplorerRootContext, ExplorerFolderContext, ExplorerResourceNotReadonlyContext, ExplorerResourceCut, IExplorerService, ExplorerResourceMoveableToTrash, ExplorerViewletVisibleContext } from 'vs/workbench/contrib/files/common/files'; import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL } from 'vs/workbench/browser/actions/workspaceCommands'; import { CLOSE_SAVED_EDITORS_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_EDITOR_COMMAND_ID, CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; import { AutoSaveContext } from 'vs/workbench/services/textfile/common/textfiles'; @@ -26,6 +26,9 @@ import { Schemas } from 'vs/base/common/network'; import { SupportsWorkspacesContext, IsWebContext, RemoteFileDialogContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { OpenFileFolderAction, OpenLocalFileFolderCommand, OpenFileAction, OpenFolderAction, OpenLocalFileCommand, OpenLocalFolderCommand, OpenWorkspaceAction, SaveLocalFileCommand } from 'vs/workbench/browser/actions/workspaceActions'; +import { ActiveEditorIsSaveableContext } from 'vs/workbench/common/editor'; +import { SidebarFocusContext } from 'vs/workbench/common/viewlet'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; // Contribute Global Actions const category = { value: nls.localize('filesCategory', "File"), original: 'File' }; @@ -225,12 +228,12 @@ function appendEditorTitleContextMenuItem(id: string, title: string, when: Conte // Editor Title Menu for Conflict Resolution appendSaveConflictEditorTitleAction('workbench.files.action.acceptLocalChanges', nls.localize('acceptLocalChanges', "Use your changes and overwrite file contents"), { - light: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/check-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/check-dark.svg`)) + light: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/files/browser/media/check-light.svg`)), + dark: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/files/browser/media/check-dark.svg`)) }, -10, acceptLocalChangesCommand); appendSaveConflictEditorTitleAction('workbench.files.action.revertLocalChanges', nls.localize('revertLocalChanges', "Discard your changes and revert to file contents"), { - light: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/undo-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/undo-dark.svg`)) + light: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/files/browser/media/undo-light.svg`)), + dark: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/files/browser/media/undo-dark.svg`)) }, -9, revertLocalChangesCommand); function appendSaveConflictEditorTitleAction(id: string, title: string, iconLocation: { dark: URI; light?: URI; }, order: number, command: ICommandHandler): void { @@ -651,7 +654,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: '4_save', command: { id: SAVE_FILE_COMMAND_ID, - title: nls.localize({ key: 'miSave', comment: ['&& denotes a mnemonic'] }, "&&Save") + title: nls.localize({ key: 'miSave', comment: ['&& denotes a mnemonic'] }, "&&Save"), + precondition: ContextKeyExpr.or(ActiveEditorIsSaveableContext, ContextKeyExpr.and(ExplorerViewletVisibleContext, SidebarFocusContext)) }, order: 1 }); @@ -660,7 +664,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: '4_save', command: { id: SAVE_FILE_AS_COMMAND_ID, - title: nls.localize({ key: 'miSaveAs', comment: ['&& denotes a mnemonic'] }, "Save &&As...") + title: nls.localize({ key: 'miSaveAs', comment: ['&& denotes a mnemonic'] }, "Save &&As..."), + precondition: ContextKeyExpr.or(ActiveEditorIsSaveableContext, ContextKeyExpr.and(ExplorerViewletVisibleContext, SidebarFocusContext)) }, order: 2 }); diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index c1c13d4a1c..c28b806038 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -938,7 +938,7 @@ async function openExplorerAndCreate(accessor: ServicesAccessor, isFolder: boole const { stat } = getContext(list); let folder: ExplorerItem; if (stat) { - folder = stat.isDirectory ? stat : stat.parent!; + folder = stat.isDirectory ? stat : (stat.parent || explorerService.roots[0]); } else { folder = explorerService.roots[0]; } @@ -952,7 +952,7 @@ async function openExplorerAndCreate(accessor: ServicesAccessor, isFolder: boole folder.addChild(newStat); - const onSuccess = async (value: string) => { + const onSuccess = (value: string): Promise => { const createPromise = isFolder ? fileService.createFolder(resources.joinPath(folder.resource, value)) : textFileService.create(resources.joinPath(folder.resource, value)); return createPromise.then(created => { refreshIfSeparator(value, explorerService); @@ -970,8 +970,6 @@ async function openExplorerAndCreate(accessor: ServicesAccessor, isFolder: boole explorerService.setEditable(newStat, null); if (success) { onSuccess(value); - } else { - explorerService.select(folder.resource).then(undefined, onUnexpectedError); } } }); diff --git a/src/vs/workbench/contrib/files/browser/media/action-close.svg b/src/vs/workbench/contrib/files/browser/media/action-close.svg deleted file mode 100644 index fde34404d4..0000000000 --- a/src/vs/workbench/contrib/files/browser/media/action-close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/files/browser/media/close-all-hc.svg b/src/vs/workbench/contrib/files/browser/media/close-all-hc.svg deleted file mode 100644 index 3cbd40ee69..0000000000 --- a/src/vs/workbench/contrib/files/browser/media/close-all-hc.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/contrib/files/browser/media/saveall.svg b/src/vs/workbench/contrib/files/browser/media/saveall.svg deleted file mode 100644 index 5f036a20f7..0000000000 --- a/src/vs/workbench/contrib/files/browser/media/saveall.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index 7e9323aaa6..3559ecad4d 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { URI } from 'vs/base/common/uri'; import * as perf from 'vs/base/common/performance'; -import { Action, IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; +import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { memoize } from 'vs/base/common/decorators'; import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocusedContext, ExplorerFocusedContext, ExplorerRootContext, ExplorerResourceReadonlyContext, IExplorerService, ExplorerResourceCut, ExplorerResourceMoveableToTrash } from 'vs/workbench/contrib/files/common/files'; import { NewFolderAction, NewFileAction, FileCopiedContext, RefreshExplorerView, CollapseExplorerView } from 'vs/workbench/contrib/files/browser/fileActions'; @@ -50,7 +50,6 @@ import { first } from 'vs/base/common/arrays'; import { withNullAsUndefined } from 'vs/base/common/types'; import { IFileService, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; import { dispose } from 'vs/base/common/lifecycle'; -import { timeout } from 'vs/base/common/async'; export class ExplorerView extends ViewletPanel { static readonly ID: string = 'workbench.explorer.fileView'; @@ -69,6 +68,7 @@ export class ExplorerView extends ViewletPanel { private shouldRefresh = true; private dragHandler!: DelayedDragHandler; private autoReveal = false; + private actions: IAction[] | undefined; constructor( options: IViewletPanelOptions, @@ -171,7 +171,12 @@ export class ExplorerView extends ViewletPanel { })); this._register(this.explorerService.onDidChangeRoots(() => this.setTreeInput())); - this._register(this.explorerService.onDidChangeItem(e => this.refresh(e.recursive, e.item))); + this._register(this.explorerService.onDidChangeItem(e => { + if (this.explorerService.isEditable(undefined)) { + this.tree.domFocus(); + } + this.refresh(e.recursive, e.item); + })); this._register(this.explorerService.onDidChangeEditable(async e => { const isEditing = !!this.explorerService.getEditableData(e); @@ -219,14 +224,16 @@ export class ExplorerView extends ViewletPanel { } getActions(): IAction[] { - const actions: Action[] = []; - - actions.push(this.instantiationService.createInstance(NewFileAction)); - actions.push(this.instantiationService.createInstance(NewFolderAction)); - actions.push(this.instantiationService.createInstance(RefreshExplorerView, RefreshExplorerView.ID, RefreshExplorerView.LABEL)); - actions.push(this.instantiationService.createInstance(CollapseExplorerView, CollapseExplorerView.ID, CollapseExplorerView.LABEL)); - - return actions; + if (!this.actions) { + this.actions = [ + this.instantiationService.createInstance(NewFileAction), + this.instantiationService.createInstance(NewFolderAction), + this.instantiationService.createInstance(RefreshExplorerView, RefreshExplorerView.ID, RefreshExplorerView.LABEL), + this.instantiationService.createInstance(CollapseExplorerView, CollapseExplorerView.ID, CollapseExplorerView.LABEL) + ]; + this.actions.forEach(a => this._register(a)); + } + return this.actions; } focus(): void { @@ -275,35 +282,35 @@ export class ExplorerView extends ViewletPanel { this._register(createFileIconThemableTreeContainerScope(container, this.themeService)); - this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, container, new ExplorerDelegate(), [filesRenderer], + this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'FileExplorer', container, new ExplorerDelegate(), [filesRenderer], this.instantiationService.createInstance(ExplorerDataSource), { - accessibilityProvider: new ExplorerAccessibilityProvider(), - ariaLabel: nls.localize('treeAriaLabel', "Files Explorer"), - identityProvider: { - getId: (stat: ExplorerItem) => { - if (stat instanceof NewExplorerItem) { - return `new:${stat.resource}`; - } - - return stat.resource; + accessibilityProvider: new ExplorerAccessibilityProvider(), + ariaLabel: nls.localize('treeAriaLabel', "Files Explorer"), + identityProvider: { + getId: (stat: ExplorerItem) => { + if (stat instanceof NewExplorerItem) { + return `new:${stat.resource}`; } - }, - keyboardNavigationLabelProvider: { - getKeyboardNavigationLabel: (stat: ExplorerItem) => { - if (this.explorerService.isEditable(stat)) { - return undefined; - } - return stat.name; + return stat.resource; + } + }, + keyboardNavigationLabelProvider: { + getKeyboardNavigationLabel: (stat: ExplorerItem) => { + if (this.explorerService.isEditable(stat)) { + return undefined; } - }, - multipleSelectionSupport: true, - filter: this.filter, - sorter: this.instantiationService.createInstance(FileSorter), - dnd: this.instantiationService.createInstance(FileDragAndDrop), - autoExpandSingleChildren: true, - additionalScrollHeight: ExplorerDelegate.ITEM_HEIGHT - }); + + return stat.name; + } + }, + multipleSelectionSupport: true, + filter: this.filter, + sorter: this.instantiationService.createInstance(FileSorter), + dnd: this.instantiationService.createInstance(FileDragAndDrop), + autoExpandSingleChildren: true, + additionalScrollHeight: ExplorerDelegate.ITEM_HEIGHT + }); this._register(this.tree); // Bind context keys @@ -335,6 +342,13 @@ export class ExplorerView extends ViewletPanel { this._register(this.tree.onContextMenu(e => this.onContextMenu(e))); + this._register(this.tree.onDidScroll(e => { + let editable = this.explorerService.getEditable(); + if (e.scrollTopChanged && editable && this.tree.getRelativeTop(editable.stat) === null) { + editable.data.onFinish('', false); + } + })); + // save view state on shutdown this._register(this.storageService.onWillSaveState(() => { this.storageService.store(ExplorerView.TREE_VIEW_STATE_STORAGE_KEY, JSON.stringify(this.tree.getViewState()), StorageScope.WORKSPACE); @@ -522,8 +536,6 @@ export class ExplorerView extends ViewletPanel { while (item && item.resource.toString() !== resource.toString()) { await this.tree.expand(item); - // Tree returns too early from the expand, need to wait for next tick #77106 - await timeout(0); item = first(values(item.children), i => isEqualOrParent(resource, i.resource)); } diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index 66b8162b4c..1ec534e70e 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -228,43 +228,37 @@ export class FilesRenderer implements ITreeRenderer 0 && !stat.isDirectory ? lastDot : value.length }); - const done = once(async (success: boolean, blur: boolean) => { + const done = once((success: boolean, finishEditing: boolean) => { label.element.style.display = 'none'; const value = inputBox.value; dispose(toDispose); - container.removeChild(label.element); - editableData.onFinish(value, success); + label.element.remove(); + if (finishEditing) { + editableData.onFinish(value, success); + } }); - // It can happen that the tree re-renders this node. When that happens, - // we're gonna get a blur event first and only after an element disposable. - // Because of that, we should setTimeout the blur handler to differentiate - // between the blur happening because of a unrender or because of a user action. - let ignoreBlur = false; - const toDispose = [ inputBox, DOM.addStandardDisposableListener(inputBox.inputElement, DOM.EventType.KEY_DOWN, (e: IKeyboardEvent) => { if (e.equals(KeyCode.Enter)) { if (inputBox.validate()) { - done(true, false); + done(true, true); } } else if (e.equals(KeyCode.Escape)) { - done(false, false); + done(false, true); } }), DOM.addDisposableListener(inputBox.inputElement, DOM.EventType.BLUR, () => { - setTimeout(() => { - if (!ignoreBlur) { - done(inputBox.isInputValid(), true); - } - }, 0); + done(inputBox.isInputValid(), true); }), label, styler ]; - return toDisposable(() => ignoreBlur = true); + return toDisposable(() => { + done(false, false); + }); } disposeElement?(element: ITreeNode, index: number, templateData: IFileTemplateData): void { @@ -636,7 +630,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { : localize('dropFolder', "Do you want to copy '{0}' or add '{0}' as a folder to the workspace?", basename(folders[0].uri)); } - const choice = await this.dialogService.show(Severity.Info, message, buttons); + const { choice } = await this.dialogService.show(Severity.Info, message, buttons); if (choice === buttons.length - 3) { return this.workspaceEditingService.addFolders(folders); } diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index 79e8bfcb63..4e8b9805f4 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -213,13 +213,13 @@ export class OpenEditorsView extends ViewletPanel { this.listLabels.clear(); } this.listLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility }); - this.list = this.instantiationService.createInstance(WorkbenchList, container, delegate, [ + this.list = this.instantiationService.createInstance(WorkbenchList, 'OpenEditors', container, delegate, [ new EditorGroupRenderer(this.keybindingService, this.instantiationService), new OpenEditorRenderer(this.listLabels, this.instantiationService, this.keybindingService, this.configurationService) ], { - identityProvider: { getId: (element: OpenEditor | IEditorGroup) => element instanceof OpenEditor ? element.getId() : element.id.toString() }, - dnd: new OpenEditorsDragAndDrop(this.instantiationService, this.editorGroupService) - }); + identityProvider: { getId: (element: OpenEditor | IEditorGroup) => element instanceof OpenEditor ? element.getId() : element.id.toString() }, + dnd: new OpenEditorsDragAndDrop(this.instantiationService, this.editorGroupService) + }); this._register(this.list); this._register(this.listLabels); diff --git a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts index 1f6628b224..23e31480b1 100644 --- a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts @@ -33,7 +33,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { private forceOpenAs: ForceOpenAs = ForceOpenAs.None; - private textModelReference: Promise> | null; + private textModelReference: Promise> | null = null; private name: string; /** diff --git a/src/vs/workbench/contrib/files/common/explorerService.ts b/src/vs/workbench/contrib/files/common/explorerService.ts index 38874db536..489ebe5014 100644 --- a/src/vs/workbench/contrib/files/common/explorerService.ts +++ b/src/vs/workbench/contrib/files/common/explorerService.ts @@ -27,7 +27,7 @@ function getFileEventsExcludes(configurationService: IConfigurationService, root } export class ExplorerService implements IExplorerService { - _serviceBrand: any; + _serviceBrand: undefined; private static readonly EXPLORER_FILE_CHANGES_REACT_DELAY = 500; // delay in ms to react to file changes to give our internal events a chance to react first @@ -140,6 +140,10 @@ export class ExplorerService implements IExplorerService { return !!this.cutItems && this.cutItems.indexOf(item) >= 0; } + getEditable(): { stat: ExplorerItem, data: IEditableData } | undefined { + return this.editable; + } + getEditableData(stat: ExplorerItem): IEditableData | undefined { return this.editable && this.editable.stat === stat ? this.editable.data : undefined; } diff --git a/src/vs/workbench/contrib/files/common/files.ts b/src/vs/workbench/contrib/files/common/files.ts index dcf8ee8fab..1c192671aa 100644 --- a/src/vs/workbench/contrib/files/common/files.ts +++ b/src/vs/workbench/contrib/files/common/files.ts @@ -41,7 +41,7 @@ export interface IEditableData { } export interface IExplorerService { - _serviceBrand: any; + _serviceBrand: undefined; readonly roots: ExplorerItem[]; readonly sortOrder: SortOrder; readonly onDidChangeRoots: Event; @@ -51,6 +51,7 @@ export interface IExplorerService { readonly onDidCopyItems: Event<{ items: ExplorerItem[], cut: boolean, previouslyCutItems: ExplorerItem[] | undefined }>; setEditable(stat: ExplorerItem, data: IEditableData | null): void; + getEditable(): { stat: ExplorerItem, data: IEditableData } | undefined; getEditableData(stat: ExplorerItem): IEditableData | undefined; // If undefined is passed checks if any element is currently being edited. isEditable(stat: ExplorerItem | undefined): boolean; diff --git a/src/vs/workbench/contrib/issue/electron-browser/issue.ts b/src/vs/workbench/contrib/issue/electron-browser/issue.ts index 9ea00e060c..e4b632984f 100644 --- a/src/vs/workbench/contrib/issue/electron-browser/issue.ts +++ b/src/vs/workbench/contrib/issue/electron-browser/issue.ts @@ -9,7 +9,7 @@ import { IssueReporterData } from 'vs/platform/issue/node/issue'; export const IWorkbenchIssueService = createDecorator('workbenchIssueService'); export interface IWorkbenchIssueService { - _serviceBrand: any; + _serviceBrand: undefined; openReporter(dataOverrides?: Partial): Promise; openProcessExplorer(): Promise; } diff --git a/src/vs/workbench/contrib/issue/electron-browser/issueService.ts b/src/vs/workbench/contrib/issue/electron-browser/issueService.ts index b4b63d7a14..8edaad3362 100644 --- a/src/vs/workbench/contrib/issue/electron-browser/issueService.ts +++ b/src/vs/workbench/contrib/issue/electron-browser/issueService.ts @@ -16,7 +16,7 @@ import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; export class WorkbenchIssueService implements IWorkbenchIssueService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @IIssueService private readonly issueService: IIssueService, diff --git a/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts b/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts index faa26f1e6c..36b15836b9 100644 --- a/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts +++ b/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts @@ -233,6 +233,7 @@ function registerLocaleDefinitionSchema(languages: string[]): void { jsonRegistry.registerSchema(localeDefinitionFileSchemaId, { id: localeDefinitionFileSchemaId, allowComments: true, + allowsTrailingCommas: true, description: 'Locale Definition file', type: 'object', default: { diff --git a/src/vs/workbench/contrib/logs/common/logs.contribution.ts b/src/vs/workbench/contrib/logs/common/logs.contribution.ts index 458c311dd8..56c6677e9d 100644 --- a/src/vs/workbench/contrib/logs/common/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/common/logs.contribution.ts @@ -8,7 +8,7 @@ import { join } from 'vs/base/common/path'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { SetLogLevelAction, OpenLogsFolderAction, OpenSessionLogFileAction } from 'vs/workbench/contrib/logs/common/logsActions'; +import { SetLogLevelAction, OpenLogsFolderAction, OpenWindowSessionLogFileAction } from 'vs/workbench/contrib/logs/common/logsActions'; import * as Constants from 'vs/workbench/contrib/logs/common/logConstants'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -49,7 +49,7 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); const devCategory = nls.localize('developer', "Developer"); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenSessionLogFileAction, OpenSessionLogFileAction.ID, OpenSessionLogFileAction.LABEL), 'Developer: Open Log File (Session)...', devCategory); + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWindowSessionLogFileAction, OpenWindowSessionLogFileAction.ID, OpenWindowSessionLogFileAction.LABEL), 'Developer: Open Browser Log File (Session)...', devCategory); } private registerNativeContributions(): void { diff --git a/src/vs/workbench/contrib/logs/common/logsActions.ts b/src/vs/workbench/contrib/logs/common/logsActions.ts index c3e0cc7618..f9e5a6b122 100644 --- a/src/vs/workbench/contrib/logs/common/logsActions.ts +++ b/src/vs/workbench/contrib/logs/common/logsActions.ts @@ -78,10 +78,10 @@ export class SetLogLevelAction extends Action { } } -export class OpenSessionLogFileAction extends Action { +export class OpenWindowSessionLogFileAction extends Action { static ID = 'workbench.action.openSessionLogFile'; - static LABEL = nls.localize('openSessionLogFile', "Open Log File (Session)..."); + static LABEL = nls.localize('openSessionLogFile', "Open Window Log File (Session)..."); constructor(id: string, label: string, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index 8d509cc9ff..198eb2b36d 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -118,6 +118,7 @@ registerAction({ group: 'navigation' }, keybinding: { + weight: KeybindingWeight.WorkbenchContrib, keys: { primary: KeyMod.CtrlCmd | KeyCode.KEY_C }, @@ -155,6 +156,7 @@ registerAction({ }, keybinding: { when: Constants.MarkerPanelFilterFocusContextKey, + weight: KeybindingWeight.WorkbenchContrib, keys: { primary: KeyMod.CtrlCmd | KeyCode.DownArrow }, @@ -167,6 +169,7 @@ registerAction({ }, keybinding: { when: Constants.MarkerPanelFocusContextKey, + weight: KeybindingWeight.WorkbenchContrib, keys: { primary: KeyMod.CtrlCmd | KeyCode.KEY_F }, @@ -339,4 +342,4 @@ class MarkersStatusBarContributions extends Disposable implements IWorkbenchCont } } -workbenchRegistry.registerWorkbenchContribution(MarkersStatusBarContributions, LifecyclePhase.Restored); \ No newline at end of file +workbenchRegistry.registerWorkbenchContribution(MarkersStatusBarContributions, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/markers/browser/markers.ts b/src/vs/workbench/contrib/markers/browser/markers.ts index 83cf642197..09ab873128 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.ts @@ -13,6 +13,8 @@ import Constants from './constants'; import { URI } from 'vs/base/common/uri'; import { groupBy } from 'vs/base/common/arrays'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { Event } from 'vs/base/common/event'; +import { ResourceMap } from 'vs/base/common/map'; export const IMarkersWorkbenchService = createDecorator('markersWorkbenchService'); @@ -22,12 +24,12 @@ export interface IFilter { } export interface IMarkersWorkbenchService { - _serviceBrand: any; + _serviceBrand: undefined; readonly markersModel: MarkersModel; } export class MarkersWorkbenchService extends Disposable implements IMarkersWorkbenchService { - _serviceBrand: any; + _serviceBrand: undefined; readonly markersModel: MarkersModel; @@ -38,17 +40,16 @@ export class MarkersWorkbenchService extends Disposable implements IMarkersWorkb super(); this.markersModel = this._register(instantiationService.createInstance(MarkersModel, this.readMarkers())); - for (const group of groupBy(this.readMarkers(), compareMarkersByUri)) { - this.markersModel.setResourceMarkers(group[0].resource, group); - } - - this._register(markerService.onMarkerChanged(resources => this.onMarkerChanged(resources))); + this.markersModel.setResourceMarkers(groupBy(this.readMarkers(), compareMarkersByUri).map(group => [group[0].resource, group])); + this._register(Event.debounce>(markerService.onMarkerChanged, (resourcesMap, resources) => { + resourcesMap = resourcesMap ? resourcesMap : new ResourceMap(); + resources.forEach(resource => resourcesMap!.set(resource, resource)); + return resourcesMap; + }, 0)(resourcesMap => this.onMarkerChanged(resourcesMap.values()))); } private onMarkerChanged(resources: URI[]): void { - for (const resource of resources) { - this.markersModel.setResourceMarkers(resource, this.readMarkers(resource)); - } + this.markersModel.setResourceMarkers(resources.map(resource => [resource, this.readMarkers(resource)])); } private readMarkers(resource?: URI): IMarker[] { diff --git a/src/vs/workbench/contrib/markers/browser/markersModel.ts b/src/vs/workbench/contrib/markers/browser/markersModel.ts index c66391d7ba..115c48cf9e 100644 --- a/src/vs/workbench/contrib/markers/browser/markersModel.ts +++ b/src/vs/workbench/contrib/markers/browser/markersModel.ts @@ -50,7 +50,7 @@ export class ResourceMarkers { @memoize get name(): string { return basename(this.resource); } - constructor(readonly id: string, readonly resource: URI, readonly markers: Marker[]) { } + constructor(readonly id: string, readonly resource: URI, public markers: Marker[]) { } } export class Marker { @@ -58,7 +58,7 @@ export class Marker { get resource(): URI { return this.marker.resource; } get range(): IRange { return this.marker; } - private _lines: string[]; + private _lines: string[] | undefined; get lines(): string[] { if (!this._lines) { this._lines = this.marker.message.split(/\r\n|\r|\n/g); @@ -90,12 +90,18 @@ export class RelatedInformation { ) { } } +export interface MarkerChangesEvent { + readonly added: ResourceMarkers[]; + readonly removed: ResourceMarkers[]; + readonly updated: ResourceMarkers[]; +} + export class MarkersModel { private cachedSortedResources: ResourceMarkers[] | undefined = undefined; - private readonly _onDidChange = new Emitter(); - readonly onDidChange: Event = this._onDidChange.event; + private readonly _onDidChange = new Emitter(); + readonly onDidChange: Event = this._onDidChange.event; get resourceMarkers(): ResourceMarkers[] { if (!this.cachedSortedResources) { @@ -115,33 +121,48 @@ export class MarkersModel { return withUndefinedAsNull(this.resourcesByUri.get(resource.toString())); } - setResourceMarkers(resource: URI, rawMarkers: IMarker[]): void { - if (isFalsyOrEmpty(rawMarkers)) { - this.resourcesByUri.delete(resource.toString()); - } else { - - const resourceMarkersId = this.id(resource.toString()); - const markersCountByKey = new Map(); - const markers = mergeSort(rawMarkers.map((rawMarker) => { - const key = IMarkerData.makeKey(rawMarker); - const index = markersCountByKey.get(key) || 0; - markersCountByKey.set(key, index + 1); - - const markerId = this.id(resourceMarkersId, key, index); - - let relatedInformation: RelatedInformation[] | undefined = undefined; - if (rawMarker.relatedInformation) { - relatedInformation = rawMarker.relatedInformation.map((r, index) => new RelatedInformation(this.id(markerId, r.resource.toString(), r.startLineNumber, r.startColumn, r.endLineNumber, r.endColumn, index), rawMarker, r)); + setResourceMarkers(resourcesMarkers: [URI, IMarker[]][]): void { + const change: MarkerChangesEvent = { added: [], removed: [], updated: [] }; + for (const [resource, rawMarkers] of resourcesMarkers) { + let resourceMarkers = this.resourcesByUri.get(resource.toString()); + if (isFalsyOrEmpty(rawMarkers)) { + if (resourceMarkers) { + this.resourcesByUri.delete(resource.toString()); + change.removed.push(resourceMarkers); } + } else { + const resourceMarkersId = this.id(resource.toString()); + const markersCountByKey = new Map(); + const markers = mergeSort(rawMarkers.map((rawMarker) => { + const key = IMarkerData.makeKey(rawMarker); + const index = markersCountByKey.get(key) || 0; + markersCountByKey.set(key, index + 1); - return new Marker(markerId, rawMarker, relatedInformation); - }), compareMarkers); + const markerId = this.id(resourceMarkersId, key, index); - this.resourcesByUri.set(resource.toString(), new ResourceMarkers(resourceMarkersId, resource, markers)); + let relatedInformation: RelatedInformation[] | undefined = undefined; + if (rawMarker.relatedInformation) { + relatedInformation = rawMarker.relatedInformation.map((r, index) => new RelatedInformation(this.id(markerId, r.resource.toString(), r.startLineNumber, r.startColumn, r.endLineNumber, r.endColumn, index), rawMarker, r)); + } + + return new Marker(markerId, rawMarker, relatedInformation); + }), compareMarkers); + + if (resourceMarkers) { + resourceMarkers.markers = markers; + change.updated.push(resourceMarkers); + } else { + resourceMarkers = new ResourceMarkers(resourceMarkersId, resource, markers); + change.added.push(resourceMarkers); + } + this.resourcesByUri.set(resource.toString(), resourceMarkers); + } } this.cachedSortedResources = undefined; - this._onDidChange.fire(resource); + if (change.added.length || change.removed.length || change.updated.length) { + this._onDidChange.fire(change); + } } private id(...values: (string | number)[]): string { diff --git a/src/vs/workbench/contrib/markers/browser/markersPanel.ts b/src/vs/workbench/contrib/markers/browser/markersPanel.ts index 89719cb974..9f99d73b74 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanel.ts @@ -12,7 +12,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Panel } from 'vs/workbench/browser/panel'; import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import Constants from 'vs/workbench/contrib/markers/browser/constants'; -import { Marker, ResourceMarkers, RelatedInformation, MarkersModel } from 'vs/workbench/contrib/markers/browser/markersModel'; +import { Marker, ResourceMarkers, RelatedInformation, MarkersModel, MarkerChangesEvent } from 'vs/workbench/contrib/markers/browser/markersModel'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { MarkersFilterActionViewItem, MarkersFilterAction, IMarkersFilterActionChangeEvent, IMarkerFilterController } from 'vs/workbench/contrib/markers/browser/markersPanelActions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -25,9 +25,9 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { localize } from 'vs/nls'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { Iterator } from 'vs/base/common/iterator'; -import { ITreeElement, ITreeNode, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree'; +import { ITreeElement, ITreeNode, ITreeContextMenuEvent, ITreeRenderer } from 'vs/base/browser/ui/tree/tree'; import { Relay, Event, Emitter } from 'vs/base/common/event'; -import { WorkbenchObjectTree, TreeResourceNavigator2 } from 'vs/platform/list/browser/listService'; +import { WorkbenchObjectTree, TreeResourceNavigator2, IListService } from 'vs/platform/list/browser/listService'; import { FilterOptions } from 'vs/workbench/contrib/markers/browser/markersFilterOptions'; import { IExpression } from 'vs/base/common/glob'; import { deepClone } from 'vs/base/common/objects'; @@ -40,27 +40,30 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; import { domEvent } from 'vs/base/browser/event'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ResourceLabels } from 'vs/workbench/browser/labels'; import { IMarker } from 'vs/platform/markers/common/markers'; import { withUndefinedAsNull } from 'vs/base/common/types'; import { MementoObject } from 'vs/workbench/common/memento'; +import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; +import { IObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTree'; +import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; function createModelIterator(model: MarkersModel): Iterator> { const resourcesIt = Iterator.fromArray(model.resourceMarkers); - return Iterator.map(resourcesIt, m => { - const markersIt = Iterator.fromArray(m.markers); + return Iterator.map(resourcesIt, m => ({ element: m, children: createResourceMarkersIterator(m) })); +} - const children = Iterator.map(markersIt, m => { - const relatedInformationIt = Iterator.from(m.relatedInformation); - const children = Iterator.map(relatedInformationIt, r => ({ element: r })); +function createResourceMarkersIterator(resourceMarkers: ResourceMarkers): Iterator> { + const markersIt = Iterator.fromArray(resourceMarkers.markers); - return { element: m, children }; - }); + return Iterator.map(markersIt, m => { + const relatedInformationIt = Iterator.from(m.relatedInformation); + const children = Iterator.map(relatedInformationIt, r => ({ element: r })); return { element: m, children }; }); + } export class MarkersPanel extends Panel implements IMarkerFilterController { @@ -68,30 +71,26 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { private lastSelectedRelativeTop: number = 0; private currentActiveResource: URI | null = null; - private tree: WorkbenchObjectTree; - private treeLabels: ResourceLabels; - private rangeHighlightDecorations: RangeHighlightDecorations; + private readonly rangeHighlightDecorations: RangeHighlightDecorations; + private readonly filter: Filter; - private actions: IAction[]; - private collapseAllAction: IAction; - private filterAction: MarkersFilterAction; - private filterInputActionViewItem: MarkersFilterActionViewItem; + private tree!: MarkersTree; + private messageBoxContainer!: HTMLElement; + private ariaLabelElement!: HTMLElement; + + private readonly collapseAllAction: IAction; + private readonly filterAction: MarkersFilterAction; + private filterInputActionViewItem: MarkersFilterActionViewItem | null = null; - private treeContainer: HTMLElement; - private messageBoxContainer: HTMLElement; - private ariaLabelElement: HTMLElement; private readonly panelState: MementoObject; private panelFoucusContextKey: IContextKey; - private filter: Filter; - private _onDidFilter = this._register(new Emitter()); readonly onDidFilter: Event = this._onDidFilter.event; private cachedFilterStats: { total: number; filtered: number; } | undefined = undefined; private currentResourceGotAddedToMarkersData: boolean = false; readonly markersViewModel: MarkersViewModel; - private disposables: IDisposable[] = []; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -110,15 +109,21 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { super(Constants.MARKERS_PANEL_ID, telemetryService, themeService, storageService); this.panelFoucusContextKey = Constants.MarkerPanelFocusContextKey.bindTo(contextKeyService); this.panelState = this.getMemento(StorageScope.WORKSPACE); - this.markersViewModel = instantiationService.createInstance(MarkersViewModel, this.panelState['multiline']); - this.markersViewModel.onDidChange(this.onDidChangeViewState, this, this.disposables); + this.markersViewModel = this._register(instantiationService.createInstance(MarkersViewModel, this.panelState['multiline'])); + this._register(this.markersViewModel.onDidChange(marker => this.onDidChangeViewState(marker))); this.setCurrentActiveEditor(); + + this.filter = new Filter(new FilterOptions()); + this.rangeHighlightDecorations = this._register(this.instantiationService.createInstance(RangeHighlightDecorations)); + + // actions + this.collapseAllAction = this._register(new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action collapse-all', true, async () => this.collapseAll())); + this.filterAction = this._register(this.instantiationService.createInstance(MarkersFilterAction, { filterText: this.panelState['filter'] || '', filterHistory: this.panelState['filterHistory'] || [], useFilesExclude: !!this.panelState['useFilesExclude'] })); } public create(parent: HTMLElement): void { super.create(parent); - this.rangeHighlightDecorations = this._register(this.instantiationService.createInstance(RangeHighlightDecorations)); dom.addClass(parent, 'markers-panel'); @@ -127,7 +132,6 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { this.createArialLabelElement(container); this.createMessageBox(container); this.createTree(container); - this.createActions(); this.createListeners(); this.updateFilter(); @@ -151,7 +155,6 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } public layout(dimension: dom.Dimension): void { - this.treeContainer.style.height = `${dimension.height}px`; this.tree.layout(dimension.height, dimension.width); if (this.filterInputActionViewItem) { this.filterInputActionViewItem.toggleLayout(dimension.width < 1200); @@ -177,10 +180,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } public getActions(): IAction[] { - if (!this.actions) { - this.createActions(); - } - return this.actions; + return [this.filterAction, this.collapseAllAction]; } public showQuickFixes(marker: Marker): void { @@ -229,18 +229,31 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { return false; } - private refreshPanel(marker?: Marker): void { + private refreshPanel(markerOrChange?: Marker | MarkerChangesEvent): void { if (this.isVisible()) { this.cachedFilterStats = undefined; - if (marker) { - this.tree.rerender(marker); + if (markerOrChange) { + if (markerOrChange instanceof Marker) { + this.tree.rerender(markerOrChange); + } else { + if (markerOrChange.added.length || markerOrChange.removed.length) { + // Reset complete tree + this.tree.setChildren(null, createModelIterator(this.markersWorkbenchService.markersModel)); + } else { + // Update resource + for (const updated of markerOrChange.updated) { + this.tree.setChildren(updated, createResourceMarkersIterator(updated)); + } + } + } } else { + // Reset complete tree this.tree.setChildren(null, createModelIterator(this.markersWorkbenchService.markersModel)); } const { total, filtered } = this.getFilterStats(); - dom.toggleClass(this.treeContainer, 'hidden', total === 0 || filtered === 0); + this.tree.toggleVisibility(total === 0 || filtered === 0); this.renderMessage(); this._onDidFilter.fire(); } @@ -257,7 +270,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { this._onDidFilter.fire(); const { total, filtered } = this.getFilterStats(); - dom.toggleClass(this.treeContainer, 'hidden', total === 0 || filtered === 0); + this.tree.toggleVisibility(total === 0 || filtered === 0); this.renderMessage(); } @@ -288,19 +301,16 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } private createTree(parent: HTMLElement): void { - this.treeContainer = dom.append(parent, dom.$('.tree-container.show-file-icons')); - const onDidChangeRenderNodeCount = new Relay>(); - this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this)); + const treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this)); const virtualDelegate = new VirtualDelegate(this.markersViewModel); const renderers = [ - this.instantiationService.createInstance(ResourceMarkersRenderer, this.treeLabels, onDidChangeRenderNodeCount.event), + this.instantiationService.createInstance(ResourceMarkersRenderer, treeLabels, onDidChangeRenderNodeCount.event), this.instantiationService.createInstance(MarkerRenderer, this.markersViewModel), this.instantiationService.createInstance(RelatedInformationRenderer) ]; - this.filter = new Filter(new FilterOptions()); const accessibilityProvider = this.instantiationService.createInstance(MarkersTreeAccessibilityProvider); const identityProvider = { @@ -309,8 +319,9 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } }; - this.tree = this.instantiationService.createInstance(WorkbenchObjectTree, - this.treeContainer, + this.tree = this._register(this.instantiationService.createInstance(MarkersTree, + 'MarkersPanel', + dom.append(parent, dom.$('.tree-container.show-file-icons')), virtualDelegate, renderers, { @@ -320,7 +331,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { dnd: new ResourceDragAndDrop(this.instantiationService), expandOnlyOnTwistieClick: (e: TreeElement) => e instanceof Marker && e.relatedInformation.length > 0 } - ); + )); onDidChangeRenderNodeCount.input = this.tree.onDidChangeRenderNodeCount; @@ -381,54 +392,34 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { })); } - private createActions(): void { - this.collapseAllAction = new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action collapse-all', true, async () => { - this.tree.collapseAll(); - this.tree.setSelection([]); - this.tree.setFocus([]); - this.tree.getHTMLElement().focus(); - this.tree.focusFirst(); - }); - - this.filterAction = this.instantiationService.createInstance(MarkersFilterAction, { filterText: this.panelState['filter'] || '', filterHistory: this.panelState['filterHistory'] || [], useFilesExclude: !!this.panelState['useFilesExclude'] }); - this.actions = [this.filterAction, this.collapseAllAction]; + private collapseAll(): void { + this.tree.collapseAll(); + this.tree.setSelection([]); + this.tree.setFocus([]); + this.tree.getHTMLElement().focus(); + this.tree.focusFirst(); } private createListeners(): void { - const onModelOrActiveEditorChanged = Event.debounce(Event.any(this.markersWorkbenchService.markersModel.onDidChange, Event.map(this.editorService.onDidActiveEditorChange, () => true)), (result, e) => { - if (!result) { - result = { - resources: [], - activeEditorChanged: false - }; - } - if (e === true) { - result.activeEditorChanged = true; + this._register(Event.any(this.markersWorkbenchService.markersModel.onDidChange, this.editorService.onDidActiveEditorChange)(changes => { + if (changes) { + this.onDidChangeModel(changes); } else { - result.resources.push(e); - } - return result; - }, 0); - - this._register(onModelOrActiveEditorChanged(({ resources, activeEditorChanged }) => { - if (resources) { - this.onDidChangeModel(resources); - } - if (activeEditorChanged) { this.onActiveEditorChanged(); } - }, this)); + })); this._register(this.tree.onDidChangeSelection(() => this.onSelected())); this._register(this.filterAction.onDidChange((event: IMarkersFilterActionChangeEvent) => { if (event.filterText || event.useFilesExclude) { this.updateFilter(); } })); - this.actions.forEach(a => this._register(a)); } - private onDidChangeModel(resources: URI[]) { - for (const resource of resources) { + private onDidChangeModel(change: MarkerChangesEvent) { + const resourceMarkers = [...change.added, ...change.removed, ...change.updated]; + const resources: URI[] = []; + for (const { resource } of resourceMarkers) { this.markersViewModel.remove(resource); const resourceMarkers = this.markersWorkbenchService.markersModel.getResourceMarkers(resource); if (resourceMarkers) { @@ -436,9 +427,10 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { this.markersViewModel.add(marker); } } + resources.push(resource); } this.currentResourceGotAddedToMarkersData = this.currentResourceGotAddedToMarkersData || this.isCurrentResourceGotAddedToMarkersData(resources); - this.refreshPanel(); + this.refreshPanel(change); this.updateRangeHighlights(); if (this.currentResourceGotAddedToMarkersData) { this.autoReveal(); @@ -483,7 +475,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { private render(): void { this.cachedFilterStats = undefined; this.tree.setChildren(null, createModelIterator(this.markersWorkbenchService.markersModel)); - dom.toggleClass(this.treeContainer, 'hidden', this.isEmpty()); + this.tree.toggleVisibility(this.isEmpty()); this.renderMessage(); } @@ -733,10 +725,33 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { super.saveState(); } - public dispose(): void { - super.dispose(); - this.tree.dispose(); - this.markersViewModel.dispose(); - this.disposables = dispose(this.disposables); - } +} + +class MarkersTree extends WorkbenchObjectTree { + + constructor( + user: string, + readonly container: HTMLElement, + delegate: IListVirtualDelegate, + renderers: ITreeRenderer[], + options: IObjectTreeOptions, + @IContextKeyService contextKeyService: IContextKeyService, + @IListService listService: IListService, + @IThemeService themeService: IThemeService, + @IConfigurationService configurationService: IConfigurationService, + @IKeybindingService keybindingService: IKeybindingService, + @IAccessibilityService accessibilityService: IAccessibilityService + ) { + super(user, container, delegate, renderers, options, contextKeyService, listService, themeService, configurationService, keybindingService, accessibilityService); + } + + layout(height: number, width: number): void { + this.container.style.height = `${height}px`; + super.layout(height, width); + } + + toggleVisibility(hide: boolean): void { + dom.toggleClass(this.container, 'hidden', hide); + } + } diff --git a/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts b/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts index d1581b32e2..13b2fdbbb7 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts @@ -118,10 +118,9 @@ export interface IMarkerFilterController { export class MarkersFilterActionViewItem extends BaseActionViewItem { private delayedFilterUpdate: Delayer; - private container: HTMLElement; - private filterInputBox: HistoryInputBox; - private controlsContainer: HTMLInputElement; - private filterBadge: HTMLInputElement; + private container: HTMLElement | null = null; + private filterInputBox: HistoryInputBox | null = null; + private filterBadge: HTMLElement | null = null; private focusContextKey: IContextKey; constructor( @@ -172,13 +171,13 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem { this.filterInputBox.inputElement.setAttribute('aria-labelledby', 'markers-panel-arialabel'); this._register(attachInputBoxStyler(this.filterInputBox, this.themeService)); this.filterInputBox.value = this.action.filterText; - this._register(this.filterInputBox.onDidChange(filter => this.delayedFilterUpdate.trigger(() => this.onDidInputChange(this.filterInputBox)))); + this._register(this.filterInputBox.onDidChange(filter => this.delayedFilterUpdate.trigger(() => this.onDidInputChange(this.filterInputBox!)))); this._register(this.action.onDidChange((event: IMarkersFilterActionChangeEvent) => { if (event.filterText) { - this.filterInputBox.value = this.action.filterText; + this.filterInputBox!.value = this.action.filterText; } })); - this._register(DOM.addStandardDisposableListener(this.filterInputBox.inputElement, DOM.EventType.KEY_DOWN, (e: any) => this.onInputKeyDown(e, this.filterInputBox))); + this._register(DOM.addStandardDisposableListener(this.filterInputBox.inputElement, DOM.EventType.KEY_DOWN, (e: any) => this.onInputKeyDown(e, this.filterInputBox!))); this._register(DOM.addStandardDisposableListener(container, DOM.EventType.KEY_DOWN, this.handleKeyboardEvent)); this._register(DOM.addStandardDisposableListener(container, DOM.EventType.KEY_UP, this.handleKeyboardEvent)); @@ -189,24 +188,24 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem { } private createControls(container: HTMLElement): void { - this.controlsContainer = DOM.append(container, DOM.$('.markers-panel-filter-controls')); - this.createBadge(this.controlsContainer); - this.createFilesExcludeCheckbox(this.controlsContainer); + const controlsContainer = DOM.append(container, DOM.$('.markers-panel-filter-controls')); + this.createBadge(controlsContainer); + this.createFilesExcludeCheckbox(controlsContainer); } private createBadge(container: HTMLElement): void { - this.filterBadge = DOM.append(container, DOM.$('.markers-panel-filter-badge')); + const filterBadge = this.filterBadge = DOM.append(container, DOM.$('.markers-panel-filter-badge')); this._register(attachStylerCallback(this.themeService, { badgeBackground, badgeForeground, contrastBorder }, colors => { const background = colors.badgeBackground ? colors.badgeBackground.toString() : null; const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : null; const border = colors.contrastBorder ? colors.contrastBorder.toString() : null; - this.filterBadge.style.backgroundColor = background; + filterBadge.style.backgroundColor = background; - this.filterBadge.style.borderWidth = border ? '1px' : null; - this.filterBadge.style.borderStyle = border ? 'solid' : null; - this.filterBadge.style.borderColor = border; - this.filterBadge.style.color = foreground; + filterBadge.style.borderWidth = border ? '1px' : null; + filterBadge.style.borderStyle = border ? 'solid' : null; + filterBadge.style.borderColor = border; + filterBadge.style.color = foreground; })); this.updateBadge(); this._register(this.filterController.onDidFilter(() => this.updateBadge())); @@ -241,14 +240,18 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem { } private updateBadge(): void { - const { total, filtered } = this.filterController.getFilterStats(); - DOM.toggleClass(this.filterBadge, 'hidden', total === filtered || filtered === 0); - this.filterBadge.textContent = localize('showing filtered problems', "Showing {0} of {1}", filtered, total); - this.adjustInputBox(); + if (this.filterBadge) { + const { total, filtered } = this.filterController.getFilterStats(); + DOM.toggleClass(this.filterBadge, 'hidden', total === filtered || filtered === 0); + this.filterBadge.textContent = localize('showing filtered problems', "Showing {0} of {1}", filtered, total); + this.adjustInputBox(); + } } private adjustInputBox(): void { - this.filterInputBox.inputElement.style.paddingRight = DOM.hasClass(this.container, 'small') || DOM.hasClass(this.filterBadge, 'hidden') ? '25px' : '150px'; + if (this.container && this.filterInputBox && this.filterBadge) { + this.filterInputBox.inputElement.style.paddingRight = DOM.hasClass(this.container, 'small') || DOM.hasClass(this.filterBadge, 'hidden') ? '25px' : '150px'; + } } // Action toolbar is swallowing some keys for action items which should not be for an input box diff --git a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index 6781a22e1b..33d1a38b53 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -510,7 +510,7 @@ export class MarkerViewModel extends Disposable { } } - private _quickFixAction: QuickFixAction; + private _quickFixAction: QuickFixAction | null = null; get quickFixAction(): QuickFixAction { if (!this._quickFixAction) { this._quickFixAction = this._register(this.instantiationService.createInstance(QuickFixAction, this.marker)); @@ -565,7 +565,7 @@ export class MarkerViewModel extends Disposable { true, () => { return this.openFileAtMarker(this.marker) - .then(() => applyCodeAction(codeAction, this.bulkEditService, this.commandService)); + .then(() => this.instantiationService.invokeFunction(applyCodeAction, codeAction, this.bulkEditService, this.commandService)); })); } @@ -616,7 +616,7 @@ export class MarkersViewModel extends Disposable { private bulkUpdate: boolean = false; - private hoveredMarker: Marker | null; + private hoveredMarker: Marker | null = null; private hoverDelayer: Delayer = new Delayer(300); constructor( diff --git a/src/vs/workbench/contrib/markers/test/electron-browser/markersModel.test.ts b/src/vs/workbench/contrib/markers/test/electron-browser/markersModel.test.ts index cc27453e1d..31b12d251b 100644 --- a/src/vs/workbench/contrib/markers/test/electron-browser/markersModel.test.ts +++ b/src/vs/workbench/contrib/markers/test/electron-browser/markersModel.test.ts @@ -20,7 +20,7 @@ class TestMarkersModel extends MarkersModel { const markers = byResource[key]; const resource = markers[0].resource; - this.setResourceMarkers(resource, markers); + this.setResourceMarkers([[resource, markers]]); }); } } diff --git a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts index a6a3532a1d..a0a3b22e1a 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts @@ -317,6 +317,7 @@ export class OutlinePanel extends ViewletPanel { this._treeComparator = new OutlineItemComparator(this._outlineViewState.sortBy); this._tree = this._instantiationService.createInstance( WorkbenchDataTree, + 'OutlinePanel', treeContainer, new OutlineVirtualDelegate(), [new OutlineGroupRenderer(), this._treeRenderer], diff --git a/src/vs/workbench/contrib/output/browser/outputPanel.ts b/src/vs/workbench/contrib/output/browser/outputPanel.ts index b5f0def7c6..ab5723a513 100644 --- a/src/vs/workbench/contrib/output/browser/outputPanel.ts +++ b/src/vs/workbench/contrib/output/browser/outputPanel.ts @@ -114,8 +114,8 @@ export class OutputPanel extends AbstractTextResourceEditor { return channel ? nls.localize('outputPanelWithInputAriaLabel', "{0}, Output panel", channel.label) : nls.localize('outputPanelAriaLabel', "Output panel"); } - public setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { - this._focus = !options.preserveFocus; + public setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { + this._focus = !(options && options.preserveFocus); if (input.matches(this.input)) { return Promise.resolve(undefined); } diff --git a/src/vs/workbench/contrib/output/browser/outputServices.ts b/src/vs/workbench/contrib/output/browser/outputServices.ts index 6b39528ef4..7d037c36bd 100644 --- a/src/vs/workbench/contrib/output/browser/outputServices.ts +++ b/src/vs/workbench/contrib/output/browser/outputServices.ts @@ -59,7 +59,7 @@ class OutputChannel extends Disposable implements IOutputChannel { export class OutputService extends Disposable implements IOutputService, ITextModelContentProvider { - public _serviceBrand: any; + public _serviceBrand: undefined; private channels: Map = new Map(); private activeChannelIdInStorage: string; diff --git a/src/vs/workbench/contrib/output/common/output.ts b/src/vs/workbench/contrib/output/common/output.ts index 3e4746d488..03be15fcb6 100644 --- a/src/vs/workbench/contrib/output/common/output.ts +++ b/src/vs/workbench/contrib/output/common/output.ts @@ -62,7 +62,7 @@ export const IOutputService = createDecorator(OUTPUT_SERVICE_ID) * The output service to manage output from the various processes running. */ export interface IOutputService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Given the channel id returns the output channel instance. diff --git a/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts b/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts index f532511aef..83155827dc 100644 --- a/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts +++ b/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts @@ -106,6 +106,11 @@ export class StartupProfiler implements IWorkbenchContribution { } private async _createPerfIssue(files: string[]): Promise { + const reportIssueUrl = product.reportIssueUrl; + if (!reportIssueUrl) { + return; + } + const ref = await this._textModelResolverService.createModelReference(PerfviewInput.Uri); await this._clipboardService.writeText(ref.object.textEditorModel.getValue()); ref.dispose(); @@ -115,7 +120,7 @@ export class StartupProfiler implements IWorkbenchContribution { 1. :warning: Make sure to **attach** these files from your *home*-directory: :warning:\n${files.map(file => `-\`${file}\``).join('\n')} `; - const baseUrl = product.reportIssueUrl; + const baseUrl = reportIssueUrl; const queryStringPrefix = baseUrl.indexOf('?') === -1 ? '?' : '&'; this._openerService.open(URI.parse(`${baseUrl}${queryStringPrefix}body=${encodeURIComponent(body)}`)); diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index bc55424f03..2294f27b83 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -127,7 +127,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.createBody(keybindingsEditorElement); } - setInput(input: KeybindingsEditorInput, options: EditorOptions, token: CancellationToken): Promise { + setInput(input: KeybindingsEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { this.keybindingsEditorContextKey.set(true); return super.setInput(input, options, token) .then(() => this.render(!!(options && options.preserveFocus))); @@ -453,7 +453,7 @@ 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)], { + this.keybindingsList = this._register(this.instantiationService.createInstance(WorkbenchList, 'KeybindingsEditor', this.keybindingsListContainer, new Delegate(), [new KeybindingItemRenderer(this, this.instantiationService)], { identityProvider: { getId: (e: IListEntry) => e.id }, ariaLabel: localize('keybindingsLabel', "Keybindings"), setRowLineHeight: false, diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts index 6cdcac9627..c44b863304 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts @@ -30,6 +30,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { KeybindingParser } from 'vs/base/common/keybindingParser'; import Severity from 'vs/base/common/severity'; import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const NLS_LAUNCH_MESSAGE = nls.localize('defineKeybinding.start', "Define Keybinding"); const NLS_KB_LAYOUT_ERROR_MESSAGE = nls.localize('defineKeybinding.kbLayoutErrorMessage', "You won't be able to produce this key combination under your current keyboard layout."); @@ -82,7 +83,7 @@ export class DefineKeybindingController extends Disposable implements editorComm this._createKeybindingDecorationRenderer(); // The button to define keybindings is shown only for the user keybindings.json - if (!this._editor.getConfiguration().readOnly) { + if (!this._editor.getOption(EditorOption.readOnly)) { this._createKeybindingWidgetRenderer(); } else { this._disposeKeybindingWidgetRenderer(); @@ -302,14 +303,12 @@ export class KeybindingEditorDecorationsRenderer extends Disposable { private _createDecoration(isError: boolean, uiLabel: string | null, usLabel: string | null, model: ITextModel, keyNode: Node): IModelDeltaDecoration { let msg: MarkdownString; let className: string; - let beforeContentClassName: string; let overviewRulerColor: ThemeColor; if (isError) { // this is the error case msg = new MarkdownString().appendText(NLS_KB_LAYOUT_ERROR_MESSAGE); className = 'keybindingError'; - beforeContentClassName = 'inlineKeybindingError'; overviewRulerColor = themeColorFromId(overviewRulerError); } else { // this is the info case @@ -335,7 +334,6 @@ export class KeybindingEditorDecorationsRenderer extends Disposable { ); } className = 'keybindingInfo'; - beforeContentClassName = 'inlineKeybindingInfo'; overviewRulerColor = themeColorFromId(overviewRulerInfo); } @@ -352,7 +350,6 @@ export class KeybindingEditorDecorationsRenderer extends Disposable { options: { stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: className, - beforeContentClassName: beforeContentClassName, hoverMessage: msg, overviewRuler: { color: overviewRulerColor, @@ -381,7 +378,7 @@ class DefineKeybindingCommand extends EditorCommand { } runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor): void { - if (!isInterestingEditorModel(editor) || editor.getConfiguration().readOnly) { + if (!isInterestingEditorModel(editor) || editor.getOption(EditorOption.readOnly)) { return; } const controller = DefineKeybindingController.get(editor); diff --git a/src/vs/workbench/contrib/preferences/browser/media/add.svg b/src/vs/workbench/contrib/preferences/browser/media/add.svg deleted file mode 100644 index bdecdb0e45..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/add.svg +++ /dev/null @@ -1 +0,0 @@ -Layer 1 \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/add_inverse.svg b/src/vs/workbench/contrib/preferences/browser/media/add_inverse.svg deleted file mode 100644 index 3475c1e196..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/add_inverse.svg +++ /dev/null @@ -1 +0,0 @@ -Layer 1 \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/clean-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/clean-dark.svg deleted file mode 100644 index 3770d63d5f..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/clean-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/clean.svg b/src/vs/workbench/contrib/preferences/browser/media/clean.svg deleted file mode 100644 index f86ec7d627..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/clean.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/collapsed-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/collapsed-dark.svg deleted file mode 100644 index cf5c3641aa..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/collapsed-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/collapsed.svg b/src/vs/workbench/contrib/preferences/browser/media/collapsed.svg deleted file mode 100644 index 3a63808c35..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/collapsed.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/edit-json-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/edit-json-dark.svg deleted file mode 100644 index 9a725bb41f..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/edit-json-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/edit-json-light.svg b/src/vs/workbench/contrib/preferences/browser/media/edit-json-light.svg deleted file mode 100644 index 1339da7ce2..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/edit-json-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/edit.svg b/src/vs/workbench/contrib/preferences/browser/media/edit.svg deleted file mode 100644 index ecde924084..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/edit.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/edit_inverse.svg b/src/vs/workbench/contrib/preferences/browser/media/edit_inverse.svg deleted file mode 100644 index da956cb2c6..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/edit_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/ellipsis-inverse.svg b/src/vs/workbench/contrib/preferences/browser/media/ellipsis-inverse.svg deleted file mode 100644 index e3337557a2..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/ellipsis-inverse.svg +++ /dev/null @@ -1 +0,0 @@ -Ellipsis_bold_16x \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/ellipsis.svg b/src/vs/workbench/contrib/preferences/browser/media/ellipsis.svg deleted file mode 100644 index e3f8562335..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/ellipsis.svg +++ /dev/null @@ -1 +0,0 @@ -Ellipsis_bold_16x \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/expanded-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/expanded-dark.svg deleted file mode 100644 index 73d41e6399..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/expanded-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/expanded.svg b/src/vs/workbench/contrib/preferences/browser/media/expanded.svg deleted file mode 100644 index 75f73adbb0..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/expanded.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/keybindings.css b/src/vs/workbench/contrib/preferences/browser/media/keybindings.css index 935d90fa26..8312899664 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/keybindings.css +++ b/src/vs/workbench/contrib/preferences/browser/media/keybindings.css @@ -41,24 +41,6 @@ } /* Editor decorations */ -.monaco-editor .inlineKeybindingInfo:before { - margin: 0.2em 0.1em 0 0.1em; - content:" "; - display:inline-block; - height:0.8em; - width:1em; - background-size: 0.9em; -} - -.monaco-editor .inlineKeybindingError:before { - margin: 0.1em 0.1em 0 0.1em; - content:" "; - display:inline-block; - height:0.8em; - width:1em; - background-size: 1em; -} - .monaco-editor .keybindingInfo { box-shadow: inset 0 0 0 1px #B9B9B9; background-color: rgba(100, 100, 250, 0.2); diff --git a/src/vs/workbench/contrib/preferences/browser/media/open-file-inverse.svg b/src/vs/workbench/contrib/preferences/browser/media/open-file-inverse.svg deleted file mode 100644 index f6302185aa..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/open-file-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/open-file.svg b/src/vs/workbench/contrib/preferences/browser/media/open-file.svg deleted file mode 100644 index d23a23c6b5..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/open-file.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/regex-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/regex-dark.svg deleted file mode 100644 index c303032e6a..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/regex-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/regex.svg b/src/vs/workbench/contrib/preferences/browser/media/regex.svg deleted file mode 100644 index c677843bee..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/regex.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css index e2f2bc6f0e..0a5232f9d4 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css +++ b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css @@ -486,6 +486,7 @@ .settings-editor > .settings-body > .settings-tree-container .setting-item-new-extensions .settings-new-extensions-button { margin: auto; + margin-bottom: 15px; width: initial; padding: 4px 10px; } diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index 45b5380b96..ffb0bf1215 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -39,6 +39,7 @@ import { ExplorerRootContext, ExplorerFolderContext } from 'vs/workbench/contrib import { ILabelService } from 'vs/platform/label/common/label'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; Registry.as(EditorExtensions.Editors).registerEditor( new EditorDescriptor( @@ -366,6 +367,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); +const PREFERENCES_EDITOR_LIGHT_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)); +const PREFERENCES_EDITOR_DARK_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`)); class PreferencesActionsContribution extends Disposable implements IWorkbenchContribution { constructor( @@ -381,8 +384,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon id: OpenGlobalKeybindingsAction.ID, title: OpenGlobalKeybindingsAction.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`)) + light: PREFERENCES_EDITOR_LIGHT_ICON_URI, + dark: PREFERENCES_EDITOR_DARK_ICON_URI } }, when: ResourceContextKey.Resource.isEqualTo(environmentService.keybindingsResource.toString()), @@ -397,8 +400,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon id: commandId, title: OpenSettings2Action.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`)) + light: PREFERENCES_EDITOR_LIGHT_ICON_URI, + dark: PREFERENCES_EDITOR_DARK_ICON_URI } }, when: ResourceContextKey.Resource.isEqualTo(environmentService.settingsResource.toString()), @@ -438,8 +441,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon id: commandId, title: OpenSettings2Action.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`)) + light: PREFERENCES_EDITOR_LIGHT_ICON_URI, + dark: PREFERENCES_EDITOR_DARK_ICON_URI } }, when: ContextKeyExpr.and(ResourceContextKey.Resource.isEqualTo(this.preferencesService.workspaceSettingsResource!.toString()), WorkbenchStateContext.isEqualTo('workspace')), @@ -466,8 +469,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon id: commandId, title: OpenSettings2Action.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`)) + light: PREFERENCES_EDITOR_LIGHT_ICON_URI, + dark: PREFERENCES_EDITOR_DARK_ICON_URI } }, when: ContextKeyExpr.and(ResourceContextKey.Resource.isEqualTo(this.preferencesService.getFolderSettingsResource(folder.uri)!.toString())), @@ -533,8 +536,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: OpenGlobalKeybindingsFileAction.ID, title: OpenGlobalKeybindingsFileAction.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`)) + light: PREFERENCES_EDITOR_LIGHT_ICON_URI, + dark: PREFERENCES_EDITOR_DARK_ICON_URI } }, when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR), @@ -817,8 +820,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, title: nls.localize('openSettingsJson', "Open Settings (JSON)"), iconLocation: { - dark: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg')), - light: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg')) + dark: PREFERENCES_EDITOR_DARK_ICON_URI, + light: PREFERENCES_EDITOR_LIGHT_ICON_URI } }, group: 'navigation', diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts index cb5c555acd..85cd5945db 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts @@ -63,15 +63,15 @@ export class PreferencesEditor extends BaseEditor { private defaultSettingsEditorContextKey: IContextKey; private defaultSettingsJSONEditorContextKey: IContextKey; private searchFocusContextKey: IContextKey; - private headerContainer: HTMLElement; - private searchWidget: SearchWidget; - private sideBySidePreferencesWidget: SideBySidePreferencesWidget; - private preferencesRenderers: PreferencesRenderersController; + private headerContainer!: HTMLElement; + private searchWidget!: SearchWidget; + private sideBySidePreferencesWidget!: SideBySidePreferencesWidget; + private preferencesRenderers!: PreferencesRenderersController; private delayedFilterLogging: Delayer; private localSearchDelayer: Delayer; private remoteSearchThrottle: ThrottledDelayer; - private _lastReportedFilter: string; + private _lastReportedFilter: string | null = null; private lastFocusedWidget: SearchWidget | SideBySidePreferencesWidget | undefined = undefined; @@ -154,7 +154,7 @@ export class PreferencesEditor extends BaseEditor { this.preferencesRenderers.editFocusedPreference(); } - setInput(newInput: EditorInput, options: SettingsEditorOptions, token: CancellationToken): Promise { + setInput(newInput: EditorInput, options: SettingsEditorOptions | undefined, token: CancellationToken): Promise { this.defaultSettingsEditorContextKey.set(true); this.defaultSettingsJSONEditorContextKey.set(true); if (options && options.query) { @@ -202,12 +202,12 @@ export class PreferencesEditor extends BaseEditor { super.clearInput(); } - protected setEditorVisible(visible: boolean, group: IEditorGroup): void { + protected setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void { this.sideBySidePreferencesWidget.setEditorVisible(visible, group); super.setEditorVisible(visible, group); } - private updateInput(newInput: PreferencesEditorInput, options: EditorOptions, token: CancellationToken): Promise { + private updateInput(newInput: PreferencesEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { return this.sideBySidePreferencesWidget.setInput(newInput.details, newInput.master, options, token).then(({ defaultPreferencesRenderer, editablePreferencesRenderer }) => { if (token.isCancellationRequested) { return; @@ -298,7 +298,7 @@ export class PreferencesEditor extends BaseEditor { return result; } - private reportFilteringUsed(filter: string, filterResult: IFilterResult | undefined): void { + private reportFilteringUsed(filter: string, filterResult: IFilterResult | null): void { if (filter && filter !== this._lastReportedFilter) { const metadata = filterResult && filterResult.metadata; const counts = filterResult && this._countById(filterResult.filteredGroups); @@ -354,20 +354,20 @@ interface IPreferencesCount { class PreferencesRenderersController extends Disposable { - private _defaultPreferencesRenderer: IPreferencesRenderer; + private _defaultPreferencesRenderer!: IPreferencesRenderer; private _defaultPreferencesRendererDisposables: IDisposable[] = []; - private _editablePreferencesRenderer: IPreferencesRenderer; + private _editablePreferencesRenderer!: IPreferencesRenderer; private _editablePreferencesRendererDisposables: IDisposable[] = []; - private _settingsNavigator: SettingsNavigator; - private _remoteFilterCancelToken: CancellationTokenSource | undefined; + private _settingsNavigator: SettingsNavigator | null = null; + private _remoteFilterCancelToken: CancellationTokenSource | null = null; private _prefsModelsForSearch = new Map(); - private _currentLocalSearchProvider: ISearchProvider; - private _currentRemoteSearchProvider: ISearchProvider | undefined; - private _lastQuery: string; - private _lastFilterResult: IFilterResult | undefined; + private _currentLocalSearchProvider: ISearchProvider | null = null; + private _currentRemoteSearchProvider: ISearchProvider | null = null; + private _lastQuery = ''; + private _lastFilterResult: IFilterResult | null = null; private readonly _onDidFilterResultsCountChange: Emitter = this._register(new Emitter()); readonly onDidFilterResultsCountChange: Event = this._onDidFilterResultsCountChange.event; @@ -382,7 +382,7 @@ class PreferencesRenderersController extends Disposable { super(); } - get lastFilterResult(): IFilterResult | undefined { + get lastFilterResult(): IFilterResult | null { return this._lastFilterResult; } @@ -445,16 +445,16 @@ class PreferencesRenderersController extends Disposable { if (this._remoteFilterCancelToken) { this._remoteFilterCancelToken.cancel(); this._remoteFilterCancelToken.dispose(); - this._remoteFilterCancelToken = undefined; + this._remoteFilterCancelToken = null; } - this._currentRemoteSearchProvider = (updateCurrentResults && this._currentRemoteSearchProvider) || this.preferencesSearchService.getRemoteSearchProvider(query); + this._currentRemoteSearchProvider = (updateCurrentResults && this._currentRemoteSearchProvider) || this.preferencesSearchService.getRemoteSearchProvider(query) || null; this._remoteFilterCancelToken = new CancellationTokenSource(); return this.filterOrSearchPreferences(query, this._currentRemoteSearchProvider!, 'nlpResult', nls.localize('nlpResult', "Natural Language Results"), 1, this._remoteFilterCancelToken.token, updateCurrentResults).then(() => { if (this._remoteFilterCancelToken) { this._remoteFilterCancelToken.dispose(); - this._remoteFilterCancelToken = undefined; + this._remoteFilterCancelToken = null; } }, err => { if (isPromiseCanceledError(err)) { @@ -489,11 +489,11 @@ class PreferencesRenderersController extends Disposable { let [editableFilterResult, defaultFilterResult] = results; if (!defaultFilterResult && editableContentOnly) { - defaultFilterResult = this.lastFilterResult; + defaultFilterResult = this.lastFilterResult!; } this.consolidateAndUpdate(defaultFilterResult, editableFilterResult); - this._lastFilterResult = defaultFilterResult; + this._lastFilterResult = withUndefinedAsNull(defaultFilterResult); return !!(defaultFilterResult && defaultFilterResult.exactMatch); }); @@ -766,7 +766,7 @@ class SideBySidePreferencesWidget extends Widget { private defaultPreferencesHeader: HTMLElement; private defaultPreferencesEditor: DefaultPreferencesEditor; - private editablePreferencesEditor: BaseEditor; + private editablePreferencesEditor: BaseEditor | null = null; private defaultPreferencesEditorContainer: HTMLElement; private editablePreferencesEditorContainer: HTMLElement; @@ -780,8 +780,8 @@ class SideBySidePreferencesWidget extends Widget { private splitview: SplitView; - private isVisible: boolean; - private group: IEditorGroup; + private isVisible = false; + private group: IEditorGroup | undefined; get minimumWidth(): number { return this.splitview.minimumSize; } get maximumWidth(): number { return this.splitview.maximumSize; } @@ -845,12 +845,12 @@ class SideBySidePreferencesWidget extends Widget { this._register(focusTracker.onDidFocus(() => this._onFocus.fire())); } - setInput(defaultPreferencesEditorInput: DefaultPreferencesEditorInput, editablePreferencesEditorInput: EditorInput, options: EditorOptions, token: CancellationToken): Promise<{ defaultPreferencesRenderer?: IPreferencesRenderer, editablePreferencesRenderer?: IPreferencesRenderer }> { + setInput(defaultPreferencesEditorInput: DefaultPreferencesEditorInput, editablePreferencesEditorInput: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<{ defaultPreferencesRenderer?: IPreferencesRenderer, editablePreferencesRenderer?: IPreferencesRenderer }> { this.getOrCreateEditablePreferencesEditor(editablePreferencesEditorInput); this.settingsTargetsWidget.settingsTarget = this.getSettingsTarget(editablePreferencesEditorInput.getResource()!); return Promise.all([ this.updateInput(this.defaultPreferencesEditor, defaultPreferencesEditorInput, DefaultSettingsEditorContribution.ID, editablePreferencesEditorInput.getResource()!, options, token), - this.updateInput(this.editablePreferencesEditor, editablePreferencesEditorInput, SettingsEditorContribution.ID, defaultPreferencesEditorInput.getResource()!, options, token) + this.updateInput(this.editablePreferencesEditor!, editablePreferencesEditorInput, SettingsEditorContribution.ID, defaultPreferencesEditorInput.getResource()!, options, token) ]) .then(([defaultPreferencesRenderer, editablePreferencesRenderer]) => { if (token.isCancellationRequested) { @@ -902,7 +902,7 @@ class SideBySidePreferencesWidget extends Widget { } } - setEditorVisible(visible: boolean, group: IEditorGroup): void { + setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void { this.isVisible = visible; this.group = group; @@ -928,7 +928,7 @@ class SideBySidePreferencesWidget extends Widget { return editor; } - private updateInput(editor: BaseEditor, input: EditorInput, editorContributionId: string, associatedPreferencesModelUri: URI, options: EditorOptions, token: CancellationToken): Promise | undefined> { + private updateInput(editor: BaseEditor, input: EditorInput, editorContributionId: string, associatedPreferencesModelUri: URI, options: EditorOptions | undefined, token: CancellationToken): Promise | undefined> { return editor.setInput(input, options, token) .then(() => { if (token.isCancellationRequested) { @@ -1034,7 +1034,7 @@ export class DefaultPreferencesEditor extends BaseTextEditor { return options; } - setInput(input: DefaultPreferencesEditorInput, options: EditorOptions, token: CancellationToken): Promise { + setInput(input: DefaultPreferencesEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { return super.setInput(input, options, token) .then(() => this.input!.resolve() .then(editorModel => { @@ -1078,7 +1078,7 @@ interface ISettingsEditorContribution extends editorCommon.IEditorContribution { abstract class AbstractSettingsEditorContribution extends Disposable implements ISettingsEditorContribution { - private preferencesRendererCreationPromise: Promise | null> | null; + private preferencesRendererCreationPromise: Promise | null> | null = null; constructor(protected editor: ICodeEditor, @IInstantiationService protected instantiationService: IInstantiationService, diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts index fb1d94c0cb..f80f7468de 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts @@ -31,6 +31,7 @@ import { IFilterResult, IPreferencesEditorModel, IPreferencesService, ISetting, import { DefaultSettingsEditorModel, SettingsEditorModel, WorkspaceConfigurationEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels'; import { IMarkerService, IMarkerData, MarkerSeverity, MarkerTag } from 'vs/platform/markers/common/markers'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface IPreferencesRenderer extends IDisposable { readonly preferencesModel: IPreferencesEditorModel; @@ -56,7 +57,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend private editSettingActionRenderer: EditSettingRenderer; private highlightMatchesRenderer: HighlightMatchesRenderer; private modelChangeDelayer: Delayer = new Delayer(200); - private associatedPreferencesModel: IPreferencesEditorModel; + private associatedPreferencesModel!: IPreferencesEditorModel; private readonly _onFocusPreference = this._register(new Emitter()); readonly onFocusPreference: Event = this._onFocusPreference.event; @@ -228,7 +229,7 @@ export class FolderSettingsRenderer extends UserSettingsRenderer implements IPre export class DefaultSettingsRenderer extends Disposable implements IPreferencesRenderer { - private _associatedPreferencesModel: IPreferencesEditorModel; + private _associatedPreferencesModel!: IPreferencesEditorModel; private settingHighlighter: SettingHighlighter; private settingsHeaderRenderer: DefaultSettingsHeaderRenderer; private settingsGroupTitleRenderer: SettingsGroupTitleRenderer; @@ -362,7 +363,7 @@ export interface HiddenAreasProvider { export class BracesHidingRenderer extends Disposable implements HiddenAreasProvider { private _result: IFilterResult | undefined; - private _settingsGroups: ISettingsGroup[]; + private _settingsGroups!: ISettingsGroup[]; constructor(private editor: ICodeEditor) { super(); @@ -444,9 +445,9 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea private readonly _onHiddenAreasChanged = this._register(new Emitter()); readonly onHiddenAreasChanged: Event = this._onHiddenAreasChanged.event; - private settingsGroups: ISettingsGroup[]; + private settingsGroups!: ISettingsGroup[]; private hiddenGroups: ISettingsGroup[] = []; - private settingsGroupTitleWidgets: SettingsGroupTitleWidget[]; + private settingsGroupTitleWidgets!: SettingsGroupTitleWidget[]; private readonly renderDisposables = this._register(new DisposableStore()); constructor(private editor: ICodeEditor, @@ -648,7 +649,7 @@ class EditSettingRenderer extends Disposable { private editPreferenceWidgetForMouseMove: EditPreferenceWidget; private settingsGroups: ISettingsGroup[] = []; - associatedPreferencesModel: IPreferencesEditorModel; + associatedPreferencesModel!: IPreferencesEditorModel; private toggleEditPreferencesForMouseMoveDelayer: Delayer; private readonly _onUpdateSetting: Emitter<{ key: string, value: any, source: IIndexedSetting }> = new Emitter<{ key: string, value: any, source: IIndexedSetting }>(); @@ -690,7 +691,7 @@ class EditSettingRenderer extends Disposable { } private onConfigurationChanged(): void { - if (!this.editor.getConfiguration().viewInfo.glyphMargin) { + if (!this.editor.getOption(EditorOption.glyphMargin)) { this.editPreferenceWidgetForCursorPosition.hide(); this.editPreferenceWidgetForMouseMove.hide(); } @@ -740,7 +741,7 @@ class EditSettingRenderer extends Disposable { private showEditPreferencesWidget(editPreferencesWidget: EditPreferenceWidget, settings: IIndexedSetting[]) { const line = settings[0].valueRange.startLineNumber; - if (this.editor.getConfiguration().viewInfo.glyphMargin && this.marginFreeFromOtherDecorations(line)) { + if (this.editor.getOption(EditorOption.glyphMargin) && this.marginFreeFromOtherDecorations(line)) { editPreferencesWidget.show(line, nls.localize('editTtile', "Edit"), settings); const editPreferenceWidgetToHide = editPreferencesWidget === this.editPreferenceWidgetForCursorPosition ? this.editPreferenceWidgetForMouseMove : this.editPreferenceWidgetForCursorPosition; editPreferenceWidgetToHide.hide(); @@ -915,7 +916,7 @@ class SettingHighlighter extends Disposable { private fixedHighlighter: RangeHighlightDecorations; private volatileHighlighter: RangeHighlightDecorations; - private highlightedSetting: ISetting; + private highlightedSetting!: ISetting; constructor(private editor: ICodeEditor, private readonly focusEventEmitter: Emitter, private readonly clearFocusEventEmitter: Emitter, @IInstantiationService instantiationService: IInstantiationService @@ -1017,12 +1018,12 @@ class UnsupportedSettingsRenderer extends Disposable { } private handleLocalUserConfiguration(setting: ISetting, configuration: IConfigurationNode, markerData: IMarkerData[]): void { - if (this.workbenchEnvironmentService.configuration.remote && configuration.scope === ConfigurationScope.MACHINE) { + if (this.workbenchEnvironmentService.configuration.remoteAuthority && (configuration.scope === ConfigurationScope.MACHINE || configuration.scope === ConfigurationScope.MACHINE_OVERRIDABLE)) { markerData.push({ severity: MarkerSeverity.Hint, tags: [MarkerTag.Unnecessary], ...setting.range, - message: nls.localize('unsupportedRemoteMachineSetting', "This setting can be applied only in remote machine settings") + message: nls.localize('unsupportedRemoteMachineSetting', "This setting cannot be applied now. It will be applied when you open local window.") }); } } @@ -1076,7 +1077,7 @@ class UnsupportedSettingsRenderer extends Disposable { severity: MarkerSeverity.Hint, tags: [MarkerTag.Unnecessary], ...setting.range, - message: nls.localize('unsupportedMachineSetting', "This setting can be applied only in user settings") + message: nls.localize('unsupportedMachineSetting', "This setting can only be applied in user settings in local window or in remote settings in remote window.") }; } @@ -1090,7 +1091,7 @@ class UnsupportedSettingsRenderer extends Disposable { class WorkspaceConfigurationRenderer extends Disposable { private decorationIds: string[] = []; - private associatedSettingsEditorModel: IPreferencesEditorModel; + private associatedSettingsEditorModel!: IPreferencesEditorModel; private renderingDelayer: Delayer = new Delayer(200); constructor(private editor: ICodeEditor, private workspaceSettingsEditorModel: SettingsEditorModel, diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts b/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts index 93719b87ae..26d4db2fe4 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts @@ -33,7 +33,7 @@ export interface IEndpointDetails { } export class PreferencesSearchService extends Disposable implements IPreferencesSearchService { - _serviceBrand: any; + _serviceBrand: undefined; private _installedExtensions: Promise; diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts index ca50155931..4da61db4e4 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts @@ -33,14 +33,15 @@ import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/p import { PANEL_ACTIVE_TITLE_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND } from 'vs/workbench/common/theme'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class SettingsHeaderWidget extends Widget implements IViewZone { - private id: string; - private _domNode: HTMLElement; + private id!: string; + private _domNode!: HTMLElement; - protected titleContainer: HTMLElement; - private messageElement: HTMLElement; + protected titleContainer!: HTMLElement; + private messageElement!: HTMLElement; constructor(protected editor: ICodeEditor, private title: string) { super(); @@ -84,9 +85,10 @@ export class SettingsHeaderWidget extends Widget implements IViewZone { } private layout(): void { - const configuration = this.editor.getConfiguration(); - this.titleContainer.style.fontSize = configuration.fontInfo.fontSize + 'px'; - if (!configuration.contribInfo.folding) { + const options = this.editor.getOptions(); + const fontInfo = options.get(EditorOption.fontInfo); + this.titleContainer.style.fontSize = fontInfo.fontSize + 'px'; + if (!options.get(EditorOption.folding)) { this.titleContainer.style.paddingLeft = '6px'; } } @@ -121,18 +123,18 @@ export class DefaultSettingsHeaderWidget extends SettingsHeaderWidget { export class SettingsGroupTitleWidget extends Widget implements IViewZone { - private id: string; - private _afterLineNumber: number; - private _domNode: HTMLElement; + private id!: string; + private _afterLineNumber!: number; + private _domNode!: HTMLElement; - private titleContainer: HTMLElement; - private icon: HTMLElement; - private title: HTMLElement; + private titleContainer!: HTMLElement; + private icon!: HTMLElement; + private title!: HTMLElement; private _onToggled = this._register(new Emitter()); readonly onToggled: Event = this._onToggled.event; - private previousPosition: Position; + private previousPosition: Position | null = null; constructor(private editor: ICodeEditor, public settingsGroup: ISettingsGroup) { super(); @@ -199,17 +201,18 @@ export class SettingsGroupTitleWidget extends Widget implements IViewZone { } private layout(): void { - const configuration = this.editor.getConfiguration(); + const options = this.editor.getOptions(); + const fontInfo = options.get(EditorOption.fontInfo); const layoutInfo = this.editor.getLayoutInfo(); this._domNode.style.width = layoutInfo.contentWidth - layoutInfo.verticalScrollbarWidth + 'px'; - this.titleContainer.style.lineHeight = configuration.lineHeight + 3 + 'px'; - this.titleContainer.style.height = configuration.lineHeight + 3 + 'px'; - this.titleContainer.style.fontSize = configuration.fontInfo.fontSize + 'px'; + this.titleContainer.style.lineHeight = options.get(EditorOption.lineHeight) + 3 + 'px'; + this.titleContainer.style.height = options.get(EditorOption.lineHeight) + 3 + 'px'; + this.titleContainer.style.fontSize = fontInfo.fontSize + 'px'; this.icon.style.minWidth = `${this.getIconSize(16)}px`; } private getIconSize(minSize: number): number { - const fontSize = this.editor.getConfiguration().fontInfo.fontSize; + const fontSize = this.editor.getOption(EditorOption.fontInfo).fontSize; return fontSize > 8 ? Math.max(fontSize, minSize) : 12; } @@ -296,11 +299,11 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { private _folder: IWorkspaceFolder | null; private _folderSettingCounts = new Map(); - private container: HTMLElement; - private anchorElement: HTMLElement; - private labelElement: HTMLElement; - private detailsElement: HTMLElement; - private dropDownElement: HTMLElement; + private container!: HTMLElement; + private anchorElement!: HTMLElement; + private labelElement!: HTMLElement; + private detailsElement!: HTMLElement; + private dropDownElement!: HTMLElement; constructor( action: IAction, @@ -391,11 +394,7 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { this.update(); if (this._action.checked) { - if ((oldFolder || !this._folder) - || (!oldFolder || this._folder) - || (oldFolder && this._folder && (oldFolder as IWorkspaceFolder).uri.toString() === (this._folder as IWorkspaceFolder).uri.toString())) { - this._action.run(this._folder); - } + this._action.run(this._folder); } } @@ -468,14 +467,14 @@ export interface ISettingsTargetsWidgetOptions { export class SettingsTargetsWidget extends Widget { - private settingsSwitcherBar: ActionBar; - private userLocalSettings: Action; - private userRemoteSettings: Action; - private workspaceSettings: Action; - private folderSettings: FolderSettingsActionViewItem; + private settingsSwitcherBar!: ActionBar; + private userLocalSettings!: Action; + private userRemoteSettings!: Action; + private workspaceSettings!: Action; + private folderSettings!: FolderSettingsActionViewItem; private options: ISettingsTargetsWidgetOptions; - private _settingsTarget: SettingsTarget; + private _settingsTarget: SettingsTarget | null = null; private readonly _onDidTargetChange = this._register(new Emitter()); readonly onDidTargetChange: Event = this._onDidTargetChange.event; @@ -517,7 +516,8 @@ export class SettingsTargetsWidget extends Widget { this.workspaceSettings = new Action('workspaceSettings', localize('workspaceSettings', "Workspace"), '.settings-tab', false, () => this.updateTarget(ConfigurationTarget.WORKSPACE)); this.workspaceSettings.tooltip = this.workspaceSettings.label; - const folderSettingsAction = new Action('folderSettings', localize('folderSettings', "Folder"), '.settings-tab', false, (folder: IWorkspaceFolder) => this.updateTarget(folder.uri)); + const folderSettingsAction = new Action('folderSettings', localize('folderSettings', "Folder"), '.settings-tab', false, + (folder: IWorkspaceFolder | null) => this.updateTarget(folder ? folder.uri : ConfigurationTarget.USER_LOCAL)); this.folderSettings = this.instantiationService.createInstance(FolderSettingsActionViewItem, folderSettingsAction); this.update(); @@ -525,11 +525,11 @@ export class SettingsTargetsWidget extends Widget { this.settingsSwitcherBar.push([this.userLocalSettings, this.userRemoteSettings, this.workspaceSettings, folderSettingsAction]); } - get settingsTarget(): SettingsTarget { + get settingsTarget(): SettingsTarget | null { return this._settingsTarget; } - set settingsTarget(settingsTarget: SettingsTarget) { + set settingsTarget(settingsTarget: SettingsTarget | null) { this._settingsTarget = settingsTarget; this.userLocalSettings.checked = ConfigurationTarget.USER_LOCAL === this.settingsTarget; this.userRemoteSettings.checked = ConfigurationTarget.USER_REMOTE === this.settingsTarget; @@ -602,12 +602,12 @@ export interface SearchOptions extends IInputOptions { export class SearchWidget extends Widget { - domNode: HTMLElement; + domNode!: HTMLElement; - private countElement: HTMLElement; - private searchContainer: HTMLElement; - inputBox: InputBox; - private controlsDiv: HTMLElement; + private countElement!: HTMLElement; + private searchContainer!: HTMLElement; + inputBox!: InputBox; + private controlsDiv!: HTMLElement; private readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; @@ -739,8 +739,8 @@ export class EditPreferenceWidget extends Disposable { static readonly GLYPH_MARGIN_CLASS_NAME = 'edit-preferences-widget'; - private _line: number; - private _preferences: T[]; + private _line: number = -1; + private _preferences: T[] = []; private _editPreferenceDecoration: string[]; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index e90005c62f..e845f40ecb 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -88,54 +88,55 @@ export class SettingsEditor2 extends BaseEditor { type === SettingValueType.Exclude; } - private defaultSettingsEditorModel: Settings2EditorModel; + // (!) Lots of props that are set once on the first render + private defaultSettingsEditorModel!: Settings2EditorModel; - private rootElement: HTMLElement; - private headerContainer: HTMLElement; - private searchWidget: SuggestEnabledInput; - private countElement: HTMLElement; - private settingsTargetsWidget: SettingsTargetsWidget; + private rootElement!: HTMLElement; + private headerContainer!: HTMLElement; + private searchWidget!: SuggestEnabledInput; + private countElement!: HTMLElement; + private settingsTargetsWidget!: SettingsTargetsWidget; - private settingsTreeContainer: HTMLElement; - private settingsTree: SettingsTree; - private settingRenderers: SettingTreeRenderers; - private tocTreeModel: TOCTreeModel; - private settingsTreeModel: SettingsTreeModel; - private noResultsMessage: HTMLElement; - private clearFilterLinkContainer: HTMLElement; + private settingsTreeContainer!: HTMLElement; + private settingsTree!: SettingsTree; + private settingRenderers!: SettingTreeRenderers; + private tocTreeModel!: TOCTreeModel; + private settingsTreeModel!: SettingsTreeModel; + private noResultsMessage!: HTMLElement; + private clearFilterLinkContainer!: HTMLElement; - private tocTreeContainer: HTMLElement; - private tocTree: TOCTree; + private tocTreeContainer!: HTMLElement; + private tocTree!: TOCTree; - private settingsAriaExtraLabelsContainer: HTMLElement; + private settingsAriaExtraLabelsContainer!: HTMLElement; private delayedFilterLogging: Delayer; private localSearchDelayer: Delayer; private remoteSearchThrottle: ThrottledDelayer; - private searchInProgress: CancellationTokenSource | null; + private searchInProgress: CancellationTokenSource | null = null; private settingFastUpdateDelayer: Delayer; private settingSlowUpdateDelayer: Delayer; - private pendingSettingUpdate: { key: string, value: any } | null; + private pendingSettingUpdate: { key: string, value: any } | null = null; private readonly viewState: ISettingsEditorViewState; - private _searchResultModel: SearchResultModel | null; + private _searchResultModel: SearchResultModel | null = null; private tocRowFocused: IContextKey; private inSettingsEditorContextKey: IContextKey; private searchFocusContextKey: IContextKey; private scheduledRefreshes: Map; - private lastFocusedSettingElement: string; + private lastFocusedSettingElement: string | null = null; /** Don't spam warnings */ - private hasWarnedMissingSettings: boolean; + private hasWarnedMissingSettings = false; private editorMemento: IEditorMemento; - private tocFocusedElement: SettingsTreeGroupElement | null; + private tocFocusedElement: SettingsTreeGroupElement | null = null; private settingsTreeScrollTop = 0; - private dimension: DOM.Dimension; + private dimension!: DOM.Dimension; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -210,7 +211,7 @@ export class SettingsEditor2 extends BaseEditor { this.updateStyles(); } - setInput(input: SettingsEditor2Input, options: SettingsEditorOptions | null, token: CancellationToken): Promise { + setInput(input: SettingsEditor2Input, options: SettingsEditorOptions | undefined, token: CancellationToken): Promise { this.inSettingsEditorContextKey.set(true); return super.setInput(input, options, token) .then(() => timeout(0)) // Force setInput to be async @@ -253,7 +254,7 @@ export class SettingsEditor2 extends BaseEditor { } } - setOptions(options: SettingsEditorOptions | null): void { + setOptions(options: SettingsEditorOptions | undefined): void { super.setOptions(options); if (options) { @@ -391,10 +392,10 @@ export class SettingsEditor2 extends BaseEditor { return SettingsEditor2.SUGGESTIONS.filter(tag => query.indexOf(tag) === -1).map(tag => strings.endsWith(tag, ':') ? tag : tag + ' '); } }, searchBoxLabel, 'settingseditor:searchinput' + SettingsEditor2.NUM_INSTANCES++, { - placeholderText: searchBoxLabel, - focusContextKey: this.searchFocusContextKey, - // TODO: Aria-live - }) + placeholderText: searchBoxLabel, + focusContextKey: this.searchFocusContextKey, + // TODO: Aria-live + }) ); this._register(this.searchWidget.onFocus(() => { @@ -471,7 +472,7 @@ export class SettingsEditor2 extends BaseEditor { return this.openSettingsFile(query.query); } - private openSettingsFile(query?: string): Promise { + private async openSettingsFile(query?: string): Promise { const currentSettingsTarget = this.settingsTargetsWidget.settingsTarget; const options: ISettingsEditorOptions = { query }; @@ -481,9 +482,11 @@ export class SettingsEditor2 extends BaseEditor { return this.preferencesService.openRemoteSettings(); } else if (currentSettingsTarget === ConfigurationTarget.WORKSPACE) { return this.preferencesService.openWorkspaceSettings(true, options); - } else { + } else if (URI.isUri(currentSettingsTarget)) { return this.preferencesService.openFolderSettings(currentSettingsTarget, true, options); } + + return undefined; } private createBody(parent: HTMLElement): void { diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index 3cc54981b0..b8585f5aa0 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -1469,7 +1469,7 @@ export class SettingsTree extends ObjectTree { ) { const treeClass = 'settings-editor-tree'; - super(container, + super('SettingsTree', container, new SettingsTreeDelegate(), renderers, { @@ -1556,8 +1556,8 @@ export class SettingsTree extends ObjectTree { })); } - protected createModel(view: ISpliceable>, options: IObjectTreeOptions): ITreeModel { - return new NonCollapsibleObjectTreeModel(view, options); + protected createModel(user: string, view: ISpliceable>, options: IObjectTreeOptions): ITreeModel { + return new NonCollapsibleObjectTreeModel(user, view, options); } } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts index ee5bf87771..c4aba3e07b 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts @@ -33,6 +33,11 @@ export abstract class SettingsTreeElement { * Index assigned in display order, used for paging. */ index: number; + + constructor(_id: string, _index: number) { + this.id = _id; + this.index = _index; + } } export type SettingsTreeGroupChild = (SettingsTreeGroupElement | SettingsTreeSettingElement | SettingsTreeNewExtensionsElement); @@ -43,8 +48,8 @@ export class SettingsTreeGroupElement extends SettingsTreeElement { level: number; isFirstGroup: boolean; - private _childSettingKeys: Set; - private _children: SettingsTreeGroupChild[]; + private _childSettingKeys: Set = new Set(); + private _children: SettingsTreeGroupChild[] = []; get children(): SettingsTreeGroupChild[] { return this._children; @@ -61,6 +66,15 @@ export class SettingsTreeGroupElement extends SettingsTreeElement { }); } + constructor(_id: string, _index: number, count: number | undefined, label: string, level: number, isFirstGroup: boolean) { + super(_id, _index); + + this.count = count; + this.label = label; + this.level = level; + this.isFirstGroup = isFirstGroup; + } + /** * Returns whether this group contains the given child key (to a depth of 1 only) */ @@ -70,7 +84,9 @@ export class SettingsTreeGroupElement extends SettingsTreeElement { } export class SettingsTreeNewExtensionsElement extends SettingsTreeElement { - extensionIds: string[]; + constructor(_id: string, _index: number, public readonly extensionIds: string[]) { + super(_id, _index); + } } export class SettingsTreeSettingElement extends SettingsTreeElement { @@ -78,8 +94,8 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { setting: ISetting; - private _displayCategory: string; - private _displayLabel: string; + private _displayCategory: string | null = null; + private _displayLabel: string | null = null; /** * scopeValue || defaultValue, for rendering convenience. @@ -99,19 +115,17 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { /** * Whether the setting is configured in the selected scope. */ - isConfigured: boolean; + isConfigured = false; tags?: Set; - overriddenScopeList: string[]; - description: string; - valueType: SettingValueType; + overriddenScopeList: string[] = []; + description!: string; + valueType!: SettingValueType; constructor(setting: ISetting, parent: SettingsTreeGroupElement, index: number, inspectResult: IInspectResult) { - super(); - this.index = index; + super(sanitizeId(parent.id + '_' + setting.key), index); this.setting = setting; this.parent = parent; - this.id = sanitizeId(parent.id + '_' + setting.key); this.update(inspectResult); } @@ -121,7 +135,7 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { this.initLabel(); } - return this._displayCategory; + return this._displayCategory!; } get displayLabel(): string { @@ -129,7 +143,7 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { this.initLabel(); } - return this._displayLabel; + return this._displayLabel!; } private initLabel(): void { @@ -270,10 +284,10 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { } export class SettingsTreeModel { - protected _root: SettingsTreeGroupElement; + protected _root!: SettingsTreeGroupElement; protected _treeElementsById = new Map(); private _treeElementsBySettingName = new Map(); - private _tocRoot: ITOCEntry; + private _tocRoot!: ITOCEntry; constructor( protected _viewState: ISettingsEditorViewState, @@ -320,13 +334,10 @@ export class SettingsTreeModel { } private createSettingsTreeGroupElement(tocEntry: ITOCEntry, parent?: SettingsTreeGroupElement): SettingsTreeGroupElement { - const element = new SettingsTreeGroupElement(); + const index = this._treeElementsById.size; - element.index = index; - element.id = tocEntry.id; - element.label = tocEntry.label; - element.parent = parent; - element.level = this.getDepth(element); + const depth = parent ? this.getDepth(parent) + 1 : 0; + const element = new SettingsTreeGroupElement(tocEntry.id, index, undefined, tocEntry.label, depth, false); const children: SettingsTreeGroupChild[] = []; if (tocEntry.settings) { @@ -482,9 +493,9 @@ export const enum SearchResultIdx { } export class SearchResultModel extends SettingsTreeModel { - private rawSearchResults: ISearchResult[]; - private cachedUniqueSearchResults: ISearchResult[] | undefined; - private newExtensionSearchResults: ISearchResult; + private rawSearchResults: ISearchResult[] | null = null; + private cachedUniqueSearchResults: ISearchResult[] | null = null; + private newExtensionSearchResults: ISearchResult | null = null; readonly id = 'searchResultModel'; @@ -526,11 +537,11 @@ export class SearchResultModel extends SettingsTreeModel { } getRawResults(): ISearchResult[] { - return this.rawSearchResults; + return this.rawSearchResults || []; } setResult(order: SearchResultIdx, result: ISearchResult | null): void { - this.cachedUniqueSearchResults = undefined; + this.cachedUniqueSearchResults = null; this.rawSearchResults = this.rawSearchResults || []; if (!result) { delete this.rawSearchResults[order]; @@ -554,17 +565,14 @@ export class SearchResultModel extends SettingsTreeModel { .filter(child => child instanceof SettingsTreeSettingElement && child.matchesAllTags(this._viewState.tagFilters) && child.matchesScope(this._viewState.settingsTarget, isRemote) && child.matchesAnyExtension(this._viewState.extensionFilters)); if (this.newExtensionSearchResults && this.newExtensionSearchResults.filterMatches.length) { - const newExtElement = new SettingsTreeNewExtensionsElement(); - newExtElement.index = this._treeElementsById.size; - newExtElement.parent = this._root; - newExtElement.id = 'newExtensions'; - this._treeElementsById.set(newExtElement.id, newExtElement); - const resultExtensionIds = this.newExtensionSearchResults.filterMatches .map(result => (result.setting)) .filter(setting => setting.extensionName && setting.extensionPublisher) .map(setting => `${setting.extensionPublisher}.${setting.extensionName}`); - newExtElement.extensionIds = arrays.distinct(resultExtensionIds); + + const newExtElement = new SettingsTreeNewExtensionsElement('newExtensions', this._treeElementsById.size, arrays.distinct(resultExtensionIds)); + newExtElement.parent = this._root; + this._treeElementsById.set(newExtElement.id, newExtElement); this._root.children.push(newExtElement); } } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts index 4a7d477253..f38a20fb26 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts @@ -136,8 +136,8 @@ type EditKey = 'none' | 'create' | number; export class ListSettingListModel { private _dataItems: IListDataItem[] = []; - private _editKey: EditKey; - private _selectedIdx: number | null; + private _editKey: EditKey | null = null; + private _selectedIdx: number | null = null; get items(): IListViewItem[] { const items = this._dataItems.map((item, i) => { @@ -457,6 +457,7 @@ export class ListSettingWidget extends Disposable { onSubmit(false); e.preventDefault(); } + rowElement.focus(); }; const valueInput = new InputBox(rowElement, this.contextViewService, { diff --git a/src/vs/workbench/contrib/preferences/browser/tocTree.ts b/src/vs/workbench/contrib/preferences/browser/tocTree.ts index 4e5d55d961..ec9f429839 100644 --- a/src/vs/workbench/contrib/preferences/browser/tocTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/tocTree.ts @@ -23,8 +23,8 @@ const $ = DOM.$; export class TOCTreeModel { - private _currentSearchModel: SearchResultModel | null; - private _settingsTreeRoot: SettingsTreeGroupElement; + private _currentSearchModel: SearchResultModel | null = null; + private _settingsTreeRoot!: SettingsTreeGroupElement; constructor( private _viewState: ISettingsEditorViewState, @@ -204,7 +204,7 @@ export class TOCTree extends ObjectTree { collapseByDefault: true }; - super(container, + super('SettingsTOC', container, new TOCTreeDelegate(), [new TOCRenderer()], options); diff --git a/src/vs/workbench/contrib/preferences/common/preferences.ts b/src/vs/workbench/contrib/preferences/common/preferences.ts index 955ac64f21..af35550cdb 100644 --- a/src/vs/workbench/contrib/preferences/common/preferences.ts +++ b/src/vs/workbench/contrib/preferences/common/preferences.ts @@ -33,7 +33,7 @@ export interface IEndpointDetails { export const IPreferencesSearchService = createDecorator('preferencesSearchService'); export interface IPreferencesSearchService { - _serviceBrand: any; + _serviceBrand: undefined; getLocalSearchProvider(filter: string): ISearchProvider; getRemoteSearchProvider(filter: string, newExtensionsOnly?: boolean): ISearchProvider | undefined; diff --git a/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts b/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts index 0a345a3e13..3ed82c8db4 100644 --- a/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts +++ b/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts @@ -26,7 +26,7 @@ import { FOLDER_SETTINGS_PATH, IPreferencesService, USE_SPLIT_JSON_SETTING } fro const schemaRegistry = Registry.as(JSONContributionRegistry.Extensions.JSONContribution); export class PreferencesContribution implements IWorkbenchContribution { - private editorOpeningListener: IDisposable; + private editorOpeningListener: IDisposable | undefined; private settingsListener: IDisposable; constructor( diff --git a/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts b/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts index 41c6a31d84..5576a1ca6b 100644 --- a/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts @@ -62,7 +62,7 @@ class CommandsHistory extends Disposable { private static readonly PREF_KEY_CACHE = 'commandPalette.mru.cache'; private static readonly PREF_KEY_COUNTER = 'commandPalette.mru.counter'; - private commandHistoryLength: number; + private commandHistoryLength = 0; constructor( @IStorageService private readonly storageService: IStorageService, @@ -217,8 +217,8 @@ class CommandPaletteEditorAction extends EditorAction { } abstract class BaseCommandEntry extends QuickOpenEntryGroup { - private description: string; - private alias: string; + private description: string | undefined; + private alias: string | undefined; private labelLowercase: string; private readonly keybindingAriaLabel?: string; @@ -258,7 +258,7 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { return this.labelLowercase; } - getDescription(): string { + getDescription(): string | undefined { return this.description; } @@ -270,7 +270,7 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { return this.keybinding; } - getDetail(): string { + getDetail(): string | undefined { return this.alias; } @@ -381,13 +381,13 @@ export class CommandsHandler extends QuickOpenHandler implements IDisposable { static readonly ID = 'workbench.picker.commands'; - private commandHistoryEnabled: boolean; + private commandHistoryEnabled: boolean | undefined; private readonly commandsHistory: CommandsHistory; private readonly disposables = new DisposableStore(); private readonly disposeOnClose = new DisposableStore(); - private waitedForExtensionsRegistered: boolean; + private waitedForExtensionsRegistered: boolean | undefined; constructor( @IEditorService private readonly editorService: IEditorService, diff --git a/src/vs/workbench/contrib/quickopen/browser/gotoLineHandler.ts b/src/vs/workbench/contrib/quickopen/browser/gotoLineHandler.ts index aa94d7d28a..e44c27019d 100644 --- a/src/vs/workbench/contrib/quickopen/browser/gotoLineHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/gotoLineHandler.ts @@ -16,7 +16,7 @@ import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IRange } from 'vs/editor/common/core/range'; import { overviewRulerRangeHighlight } from 'vs/editor/common/view/editorColorRegistry'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; -import { IEditorOptions, RenderLineNumbersType } from 'vs/editor/common/config/editorOptions'; +import { IEditorOptions, RenderLineNumbersType, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -50,8 +50,9 @@ export class GotoLineAction extends QuickOpenAction { let restoreOptions: IEditorOptions | null = null; if (isCodeEditor(activeTextEditorWidget)) { - const config = activeTextEditorWidget.getConfiguration(); - if (config.viewInfo.renderLineNumbers === RenderLineNumbersType.Relative) { + const options = activeTextEditorWidget.getOptions(); + const lineNumbers = options.get(EditorOption.lineNumbers); + if (lineNumbers.renderType === RenderLineNumbersType.Relative) { activeTextEditorWidget.updateOptions({ lineNumbers: 'on' }); diff --git a/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts b/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts index 16d112e4d7..62c94d58ae 100644 --- a/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts @@ -97,9 +97,11 @@ class OutlineModel extends QuickOpenModel { } }); - this.entries.sort(SymbolEntry.compareByRank); - - + // select comparator based on the presence of the colon-prefix + this.entries.sort(searchValuePos === 0 + ? SymbolEntry.compareByRank + : SymbolEntry.compareByKindAndRank + ); // Mark all type groups const visibleResults = this.getEntries(true); @@ -297,7 +299,7 @@ class SymbolEntry extends EditorQuickOpenEntryGroup { const kindB = NLS_SYMBOL_KIND_CACHE[b.getKind()] || FALLBACK_NLS_SYMBOL_KIND; let r = kindA.localeCompare(kindB); if (r === 0) { - r = this.compareByRank(a, b); + r = SymbolEntry.compareByRank(a, b); } return r; } diff --git a/src/vs/workbench/contrib/quickopen/browser/viewPickerHandler.ts b/src/vs/workbench/contrib/quickopen/browser/viewPickerHandler.ts index fe1662648b..e083ec6351 100644 --- a/src/vs/workbench/contrib/quickopen/browser/viewPickerHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/viewPickerHandler.ts @@ -9,7 +9,7 @@ import { QuickOpenModel, QuickOpenEntryGroup, QuickOpenEntry } from 'vs/base/par import { QuickOpenHandler, QuickOpenAction } from 'vs/workbench/browser/quickopen'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IOutputService } from 'vs/workbench/contrib/output/common/output'; -import { ITerminalService } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { Action } from 'vs/base/common/actions'; diff --git a/src/vs/workbench/contrib/relauncher/common/relauncher.contribution.ts b/src/vs/workbench/contrib/relauncher/common/relauncher.contribution.ts index f24cb52551..019ecca7bb 100644 --- a/src/vs/workbench/contrib/relauncher/common/relauncher.contribution.ts +++ b/src/vs/workbench/contrib/relauncher/common/relauncher.contribution.ts @@ -29,15 +29,15 @@ interface IConfiguration extends IWindowsConfiguration { export class SettingsChangeRelauncher extends Disposable implements IWorkbenchContribution { - private titleBarStyle: 'native' | 'custom'; - private nativeTabs: boolean; - private nativeFullScreen: boolean; - private clickThroughInactive: boolean; - private updateMode: string; - private enableCrashReporter: boolean; - private treeHorizontalScrolling: boolean; - private useGridLayout: boolean; - private debugConsoleWordWrap: boolean; + private titleBarStyle: 'native' | 'custom' | undefined; + private nativeTabs: boolean | undefined; + private nativeFullScreen: boolean | undefined; + private clickThroughInactive: boolean | undefined; + private updateMode: string | undefined; + private enableCrashReporter: boolean | undefined; + private treeHorizontalScrolling: boolean | undefined; + private useGridLayout: boolean | undefined; + private debugConsoleWordWrap: boolean | undefined; constructor( @IWindowsService private readonly windowsService: IWindowsService, diff --git a/src/vs/workbench/contrib/remote/browser/remote.ts b/src/vs/workbench/contrib/remote/browser/remote.ts index 2682bec785..8da04bcf76 100644 --- a/src/vs/workbench/contrib/remote/browser/remote.ts +++ b/src/vs/workbench/contrib/remote/browser/remote.ts @@ -33,7 +33,11 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions' import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; +import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ShowViewletAction } from 'vs/workbench/browser/viewlet'; +import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; +import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; interface HelpInformation { extensionDescription: IExtensionDescription; @@ -311,6 +315,7 @@ class HelpPanel extends ViewletPanel { container.appendChild(treeContainer); this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, + 'RemoteHelp', treeContainer, new HelpTreeVirtualDelegate(), [new HelpTreeRenderer()], @@ -421,3 +426,22 @@ Registry.as(ViewletExtensions.Viewlets).registerViewlet(new Vie 'remote', 4 )); + +class OpenRemoteViewletAction extends ShowViewletAction { + + static readonly ID = VIEWLET_ID; + static LABEL = nls.localize('toggleRemoteViewlet', "Show Remote Explorer"); + + constructor(id: string, label: string, @IViewletService viewletService: IViewletService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService) { + super(id, label, VIEWLET_ID, viewletService, editorGroupService, layoutService); + } +} + +// Register Action to Open Viewlet +Registry.as(WorkbenchActionExtensions.WorkbenchActions).registerWorkbenchAction( + new SyncActionDescriptor(OpenRemoteViewletAction, VIEWLET_ID, nls.localize('toggleRemoteViewlet', "Show Remote Explorer"), { + primary: 0 + }), + 'View: Show Remote Explorer', + nls.localize('view', "View") +); diff --git a/src/vs/workbench/contrib/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts index 5925e614eb..5258b62995 100644 --- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts @@ -7,7 +7,7 @@ import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as import { Registry } from 'vs/platform/registry/common/platform'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { ILabelService } from 'vs/platform/label/common/label'; -import { OperatingSystem } from 'vs/base/common/platform'; +import { OperatingSystem, isWeb } from 'vs/base/common/platform'; import { Schemas } from 'vs/base/common/network'; import { IRemoteAgentService, RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService'; import { ILogService } from 'vs/platform/log/common/log'; @@ -61,7 +61,8 @@ export class LabelContribution implements IWorkbenchContribution { label: '${path}', separator: remoteEnvironment.os === OperatingSystem.Windows ? '\\' : '/', tildify: remoteEnvironment.os !== OperatingSystem.Windows, - normalizeDriveLetter: remoteEnvironment.os === OperatingSystem.Windows + normalizeDriveLetter: remoteEnvironment.os === OperatingSystem.Windows, + workspaceSuffix: isWeb ? undefined : Schemas.vscodeRemote } }); } 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 fc0384d346..8838e40772 100644 --- a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -416,9 +416,9 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution { hideProgress(); progressReporter = null; - dialogService.show(Severity.Error, nls.localize('reconnectionPermanentFailure', "Cannot reconnect. Please reload the window."), [nls.localize('reloadWindow', "Reload Window"), nls.localize('cancel', "Cancel")], { cancelId: 1 }).then(choice => { + dialogService.show(Severity.Error, nls.localize('reconnectionPermanentFailure', "Cannot reconnect. Please reload the window."), [nls.localize('reloadWindow', "Reload Window"), nls.localize('cancel', "Cancel")], { cancelId: 1 }).then(result => { // Reload the window - if (choice === 0) { + if (result.choice === 0) { commandService.executeCommand(ReloadWindowAction.ID); } }); diff --git a/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts b/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts deleted file mode 100644 index d5596ca1d1..0000000000 --- a/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts +++ /dev/null @@ -1,86 +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 { URI } from 'vs/base/common/uri'; - -//https://stackoverflow.com/questions/56356655/structuring-a-typescript-project-with-workers/56374158#56374158 -declare var self: ServiceWorkerGlobalScope; - -//#region --- installing/activating - -self.addEventListener('install', _event => { - console.log('SW#install'); - self.skipWaiting(); -}); - -self.addEventListener('activate', event => { - console.log('SW#activate'); - event.waitUntil((async () => { - // (1) enable navigation preloads! - // (2) delete caches with each new version - // (3) become available to all pages - if (self.registration.navigationPreload) { - await self.registration.navigationPreload.enable(); - } - await caches.delete(_cacheName); - await self.clients.claim(); - })()); -}); - -//#endregion - -//#region --- fetching/caching - -const _cacheName = 'vscode-extension-resources'; -const _resourcePrefix = '/vscode-remote-resource'; -const _pendingFetch = new Map(); - -self.addEventListener('message', event => { - const fn = _pendingFetch.get(event.data.token); - if (fn) { - fn(event.data.data, event.data.isExtensionResource); - _pendingFetch.delete(event.data.token); - } -}); - -self.addEventListener('fetch', async (event: FetchEvent) => { - - const uri = URI.parse(event.request.url); - if (uri.path !== _resourcePrefix) { - // not a /vscode-resources/fetch-url and therefore - // not (yet?) interesting for us - event.respondWith(respondWithDefault(event)); - return; - } - - event.respondWith(respondWithResource(event, uri)); -}); - -async function respondWithDefault(event: FetchEvent): Promise { - if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { - // https://bugs.chromium.org/p/chromium/issues/detail?id=823392 - // https://stackoverflow.com/questions/48463483/what-causes-a-failed-to-execute-fetch-on-serviceworkerglobalscope-only-if#49719964 - // https://developer.mozilla.org/en-US/docs/Web/API/Request/cache - return new Response(undefined, { status: 504, statusText: 'Gateway Timeout (dev tools: https://bugs.chromium.org/p/chromium/issues/detail?id=823392)' }); - } - return await event.preloadResponse || await fetch(event.request); -} - -async function respondWithResource(event: FetchEvent, uri: URI): Promise { - - const cachedValue = await caches.open(_cacheName).then(cache => cache.match(event.request)); - if (cachedValue) { - return cachedValue; - } - - const response: Response = await event.preloadResponse || await fetch(event.request); - if (response.headers.get('X-VSCode-Extension') === 'true') { - await caches.open(_cacheName).then(cache => cache.put(event.request, response.clone())); - } - - return response; -} - -//#endregion diff --git a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts b/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts deleted file mode 100644 index f45cf904e4..0000000000 --- a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts +++ /dev/null @@ -1,49 +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 { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; -import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { ILogService } from 'vs/platform/log/common/log'; -import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; - -class ResourceServiceWorker { - - private static _url = require.toUrl('./resourceServiceWorkerMain.js'); - - private readonly _disposables = new DisposableStore(); - - constructor( - @ILogService private readonly _logService: ILogService, - ) { - navigator.serviceWorker.register(ResourceServiceWorker._url, { scope: '/' }).then(reg => { - this._logService.trace('SW#reg', reg); - return reg.update(); - }).then(() => { - this._logService.info('SW#ready'); - }).catch(err => { - this._logService.error('SW#init', err); - }); - - const handler = (e: ExtendableMessageEvent) => this._handleMessage(e); - navigator.serviceWorker.addEventListener('message', handler); - this._disposables.add(toDisposable(() => navigator.serviceWorker.removeEventListener('message', handler))); - } - - dispose(): void { - this._disposables.dispose(); - } - - private _handleMessage(event: ExtendableMessageEvent): void { - this._logService.trace('SW', event.data); - } -} - -Registry.as(Extensions.Workbench).registerWorkbenchContribution( - ResourceServiceWorker, - LifecyclePhase.Ready -); - - diff --git a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts b/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts deleted file mode 100644 index fc2b4ade1d..0000000000 --- a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts +++ /dev/null @@ -1,26 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -// This file is to bootstrap AMD so that we can program as usual -// Note the fetch, install, activate event handler must be registered -// when loading the service worker and despite AMD's async nature this -// works. That's because the/our AMD loader uses the sync importScripts -// statement. - -// trigger service worker updates -const _tag = '23549971-9b8d-41bb-92ae-d7f6a68c9702'; - -// loader world -const baseUrl = '../../../../../'; -importScripts(baseUrl + 'vs/loader.js'); -require.config({ - baseUrl, - catchError: true -}); -require(['vs/workbench/contrib/resources/browser/resourceServiceWorker'], - () => { }, - err => console.error(err) -); - diff --git a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts index c0c0f5b97b..c986da1d35 100644 --- a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts @@ -33,7 +33,7 @@ import { rot } from 'vs/base/common/numbers'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { peekViewBorder, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/referenceSearch/referencesWidget'; import { EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; -import { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IDiffEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Action, IAction, ActionRunner } from 'vs/base/common/actions'; import { IActionBarOptions, ActionsOrientation, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -223,7 +223,7 @@ class DirtyDiffWidget extends PeekViewWidget { const position = new Position(getModifiedEndLineNumber(change), 1); - const lineHeight = this.editor.getConfiguration().lineHeight; + const lineHeight = this.editor.getOption(EditorOption.lineHeight); const editorHeight = this.editor.getLayoutInfo().height; const editorHeightInLines = Math.floor(editorHeight / lineHeight); const height = Math.min(getChangeHeight(change) + /* padding */ 8, Math.floor(editorHeightInLines / 3)); diff --git a/src/vs/workbench/contrib/scm/browser/media/check-inverse.svg b/src/vs/workbench/contrib/scm/browser/media/check-inverse.svg deleted file mode 100644 index c225b2f597..0000000000 --- a/src/vs/workbench/contrib/scm/browser/media/check-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/scm/browser/media/check.svg b/src/vs/workbench/contrib/scm/browser/media/check.svg deleted file mode 100644 index d45df06edf..0000000000 --- a/src/vs/workbench/contrib/scm/browser/media/check.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts index f336011713..7732e6b4a0 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts @@ -20,7 +20,7 @@ import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, ContextKeyExpr, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { MenuItemAction, IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'; @@ -243,7 +243,7 @@ export class MainPanel extends ViewletPanel { const renderer = this.instantiationService.createInstance(ProviderRenderer); const identityProvider = { getId: (r: ISCMRepository) => r.provider.id }; - this.list = this.instantiationService.createInstance(WorkbenchList, container, delegate, [renderer], { + this.list = this.instantiationService.createInstance(WorkbenchList, `SCM Main`, container, delegate, [renderer], { identityProvider, horizontalScrolling: false }); @@ -495,7 +495,7 @@ class ResourceRenderer implements IListRenderer const theme = this.themeService.getTheme(); const icon = theme.type === LIGHT ? resource.decorations.icon : resource.decorations.iconDark; - template.fileLabel.setFile(resource.sourceUri, { fileDecorations: { colors: false, badges: !icon, data: resource.decorations } }); + template.fileLabel.setFile(resource.sourceUri, { fileDecorations: { colors: false, badges: !icon } }); template.actionBar.clear(); template.actionBar.context = resource; @@ -848,7 +848,7 @@ export class RepositoryPanel extends ViewletPanel { new ResourceRenderer(this.listLabels, actionViewItemProvider, () => this.getSelectedResources(), this.themeService, this.menus) ]; - this.list = this.instantiationService.createInstance(WorkbenchList, this.listContainer, delegate, renderers, { + this.list = this.instantiationService.createInstance(WorkbenchList, `SCM Repo`, this.listContainer, delegate, renderers, { identityProvider: scmResourceIdentityProvider, keyboardNavigationLabelProvider: scmKeyboardNavigationLabelProvider, horizontalScrolling: false @@ -1030,9 +1030,10 @@ class MainPanelDescriptor implements IViewDescriptor { readonly name = MainPanel.TITLE; readonly ctorDescriptor: { ctor: any, arguments?: any[] }; readonly canToggleVisibility = true; - readonly hideByDefault = true; + readonly hideByDefault = false; readonly order = -1000; readonly workspace = true; + readonly when = ContextKeyExpr.or(ContextKeyExpr.equals('config.scm.alwaysShowProviders', true), ContextKeyExpr.and(ContextKeyExpr.notEquals('scm.providerCount', 0), ContextKeyExpr.notEquals('scm.providerCount', 1))); constructor(viewModel: IViewModel) { this.ctorDescriptor = { ctor: MainPanel, arguments: [viewModel] }; @@ -1043,13 +1044,12 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { private static readonly STATE_KEY = 'workbench.scm.views.state'; - private repositoryCount = 0; private el: HTMLElement; private message: HTMLElement; private menus: SCMMenus; private _repositories: ISCMRepository[] = []; - private mainPanelDescriptor = new MainPanelDescriptor(this); + private repositoryCountKey: IContextKey; private viewDescriptors: RepositoryViewDescriptor[] = []; private _onDidSplice = new Emitter>(); @@ -1072,40 +1072,6 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { return Event.map(modificationEvent, () => this.visibleRepositories); } - setVisibleRepositories(repositories: ISCMRepository[]): void { - const visibleViewDescriptors = this.viewsModel.visibleViewDescriptors; - - const toSetVisible = this.viewsModel.viewDescriptors - .filter((d): d is RepositoryViewDescriptor => d instanceof RepositoryViewDescriptor && repositories.indexOf(d.repository) > -1 && visibleViewDescriptors.indexOf(d) === -1); - - const toSetInvisible = visibleViewDescriptors - .filter((d): d is RepositoryViewDescriptor => d instanceof RepositoryViewDescriptor && repositories.indexOf(d.repository) === -1); - - let size: number | undefined; - const oneToOne = toSetVisible.length === 1 && toSetInvisible.length === 1; - - for (const viewDescriptor of toSetInvisible) { - if (oneToOne) { - const panel = this.panels.filter(panel => panel.id === viewDescriptor.id)[0]; - - if (panel) { - size = this.getPanelSize(panel); - } - } - - viewDescriptor.repository.setSelected(false); - this.viewsModel.setVisible(viewDescriptor.id, false); - } - - for (const viewDescriptor of toSetVisible) { - viewDescriptor.repository.setSelected(true); - this.viewsModel.setVisible(viewDescriptor.id, true, size); - } - } - - private readonly _onDidChangeRepositories = new Emitter(); - private readonly onDidFinishStartup = Event.once(Event.debounce(this._onDidChangeRepositories.event, () => null, 1000)); - constructor( @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @ITelemetryService telemetryService: ITelemetryService, @@ -1121,6 +1087,7 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { @IConfigurationService configurationService: IConfigurationService, @IExtensionService extensionService: IExtensionService, @IWorkspaceContextService protected contextService: IWorkspaceContextService, + @IContextKeyService contextKeyService: IContextKeyService, ) { super(VIEWLET_ID, SCMViewlet.STATE_KEY, true, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); @@ -1129,13 +1096,16 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { this.message = $('.empty-message', { tabIndex: 0 }, localize('no open repo', "No source control providers registered.")); + const viewsRegistry = Registry.as(Extensions.ViewsRegistry); + viewsRegistry.registerViews([new MainPanelDescriptor(this)], VIEW_CONTAINER); + this._register(configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('scm.alwaysShowProviders')) { - this.onDidChangeRepositories(); + if (e.affectsConfiguration('scm.alwaysShowProviders') && configurationService.getValue('scm.alwaysShowProviders')) { + this.viewsModel.setVisible(MainPanel.ID, true); } })); - this._register(this.onDidFinishStartup(this.onAfterStartup, this)); + this.repositoryCountKey = contextKeyService.createKey('scm.providerCount', 0); this._register(this.viewsModel.onDidRemove(this.onDidHideView, this)); } @@ -1185,44 +1155,20 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { private onDidChangeRepositories(): void { const repositoryCount = this.repositories.length; - - const viewsRegistry = Registry.as(Extensions.ViewsRegistry); - if (this.repositoryCount === 0 && repositoryCount !== 0) { - viewsRegistry.registerViews([this.mainPanelDescriptor], VIEW_CONTAINER); - } else if (this.repositoryCount !== 0 && repositoryCount === 0) { - viewsRegistry.deregisterViews([this.mainPanelDescriptor], VIEW_CONTAINER); - } - - const alwaysShowProviders = this.configurationService.getValue('scm.alwaysShowProviders') || false; - - if (alwaysShowProviders && repositoryCount > 0) { - this.viewsModel.setVisible(MainPanel.ID, true); - } - toggleClass(this.el, 'empty', repositoryCount === 0); - this.repositoryCount = repositoryCount; - - this._onDidChangeRepositories.fire(); - } - - private onAfterStartup(): void { - if (this.repositoryCount > 0 && this.viewDescriptors.every(d => !this.viewsModel.isVisible(d.id))) { - this.viewsModel.setVisible(this.viewDescriptors[0].id, true); - } + this.repositoryCountKey.set(repositoryCount); } private onDidHideView(): void { nextTick(() => { - if (this.repositoryCount > 0 && this.viewDescriptors.every(d => !this.viewsModel.isVisible(d.id))) { - const alwaysShowProviders = this.configurationService.getValue('scm.alwaysShowProviders') || false; - this.viewsModel.setVisible(MainPanel.ID, alwaysShowProviders || this.repositoryCount > 1); + if (this.repositoryCountKey.get()! > 0 && this.viewDescriptors.every(d => !this.viewsModel.isVisible(d.id))) { this.viewsModel.setVisible(this.viewDescriptors[0].id, true); } }); } focus(): void { - if (this.repositoryCount === 0) { + if (this.repositoryCountKey.get()! === 0) { this.message.focus(); } else { const repository = this.visibleRepositories[0]; @@ -1286,4 +1232,35 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { return this.repositories[0].provider; } } + + setVisibleRepositories(repositories: ISCMRepository[]): void { + const visibleViewDescriptors = this.viewsModel.visibleViewDescriptors; + + const toSetVisible = this.viewsModel.viewDescriptors + .filter((d): d is RepositoryViewDescriptor => d instanceof RepositoryViewDescriptor && repositories.indexOf(d.repository) > -1 && visibleViewDescriptors.indexOf(d) === -1); + + const toSetInvisible = visibleViewDescriptors + .filter((d): d is RepositoryViewDescriptor => d instanceof RepositoryViewDescriptor && repositories.indexOf(d.repository) === -1); + + let size: number | undefined; + const oneToOne = toSetVisible.length === 1 && toSetInvisible.length === 1; + + for (const viewDescriptor of toSetInvisible) { + if (oneToOne) { + const panel = this.panels.filter(panel => panel.id === viewDescriptor.id)[0]; + + if (panel) { + size = this.getPanelSize(panel); + } + } + + viewDescriptor.repository.setSelected(false); + this.viewsModel.setVisible(viewDescriptor.id, false); + } + + for (const viewDescriptor of toSetVisible) { + viewDescriptor.repository.setSelected(true); + this.viewsModel.setVisible(viewDescriptor.id, true, size); + } + } } diff --git a/src/vs/workbench/contrib/scm/common/scm.ts b/src/vs/workbench/contrib/scm/common/scm.ts index a12473d3dc..51675a614b 100644 --- a/src/vs/workbench/contrib/scm/common/scm.ts +++ b/src/vs/workbench/contrib/scm/common/scm.ts @@ -10,7 +10,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Command } from 'vs/editor/common/modes'; -import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; import { ISequence } from 'vs/base/common/sequence'; export const VIEWLET_ID = 'workbench.view.scm'; @@ -28,10 +27,6 @@ export interface ISCMResourceDecorations { tooltip?: string; strikeThrough?: boolean; faded?: boolean; - - source?: string; - letter?: string; - color?: ColorIdentifier; } export interface ISCMResource { @@ -112,7 +107,7 @@ export interface ISCMRepository extends IDisposable { export interface ISCMService { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; readonly onDidAddRepository: Event; readonly onDidRemoveRepository: Event; diff --git a/src/vs/workbench/contrib/scm/common/scmService.ts b/src/vs/workbench/contrib/scm/common/scmService.ts index 2c6679a21e..02996342d9 100644 --- a/src/vs/workbench/contrib/scm/common/scmService.ts +++ b/src/vs/workbench/contrib/scm/common/scmService.ts @@ -105,7 +105,7 @@ class SCMRepository implements ISCMRepository { export class SCMService implements ISCMService { - _serviceBrand: any; + _serviceBrand: undefined; private _providerIds = new Set(); private _repositories: ISCMRepository[] = []; diff --git a/src/vs/workbench/contrib/search/browser/openAnythingHandler.ts b/src/vs/workbench/contrib/search/browser/openAnythingHandler.ts index 94a7f0b8de..d7f244ea48 100644 --- a/src/vs/workbench/contrib/search/browser/openAnythingHandler.ts +++ b/src/vs/workbench/contrib/search/browser/openAnythingHandler.ts @@ -40,10 +40,10 @@ export class OpenAnythingHandler extends QuickOpenHandler { private openSymbolHandler: OpenSymbolHandler; private openFileHandler: OpenFileHandler; - private searchDelayer: ThrottledDelayer; - private isClosed: boolean; + private searchDelayer: ThrottledDelayer; + private isClosed: boolean | undefined; private scorerCache: ScorerCache; - private includeSymbols: boolean; + private includeSymbols: boolean | undefined; constructor( @INotificationService private readonly notificationService: INotificationService, @@ -83,7 +83,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { }); } - getResults(searchValue: string, token: CancellationToken): Promise { + getResults(searchValue: string, token: CancellationToken): Promise { this.isClosed = false; // Treat this call as the handler being in use // Find a suitable range from the pattern looking for ":" and "#" @@ -99,7 +99,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { } // The throttler needs a factory for its promises - const resultsPromise = () => { + const resultsPromise = (): Promise => { const resultPromises: Promise[] = []; // File Results diff --git a/src/vs/workbench/contrib/search/browser/openFileHandler.ts b/src/vs/workbench/contrib/search/browser/openFileHandler.ts index c69bc35dc7..8cc9c4378f 100644 --- a/src/vs/workbench/contrib/search/browser/openFileHandler.ts +++ b/src/vs/workbench/contrib/search/browser/openFileHandler.ts @@ -114,7 +114,7 @@ export interface IOpenFileOptions { export class OpenFileHandler extends QuickOpenHandler { private options: IOpenFileOptions | undefined; private queryBuilder: QueryBuilder; - private cacheState: CacheState; + private cacheState: CacheState | undefined; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -143,7 +143,7 @@ export class OpenFileHandler extends QuickOpenHandler { } // Do find results - return this.doFindResults(query, token, this.cacheState.cacheKey, maxSortedResults); + return this.doFindResults(query, token, this.cacheState ? this.cacheState.cacheKey : undefined, maxSortedResults); } private async doFindResults(query: IPreparedQuery, token: CancellationToken, cacheKey?: string, maxSortedResults?: number): Promise { @@ -246,7 +246,7 @@ export class OpenFileHandler extends QuickOpenHandler { } get isCacheLoaded(): boolean { - return this.cacheState && this.cacheState.isLoaded; + return !!this.cacheState && this.cacheState.isLoaded; } getGroupLabel(): string { @@ -279,14 +279,14 @@ export class CacheState { private loadingPhase = LoadingPhase.Created; private promise: Promise | undefined; - constructor(cacheQuery: (cacheKey: string) => IFileQuery, private doLoad: (query: IFileQuery) => Promise, private doDispose: (cacheKey: string) => Promise, private previous: CacheState | null) { + constructor(cacheQuery: (cacheKey: string) => IFileQuery, private doLoad: (query: IFileQuery) => Promise, private doDispose: (cacheKey: string) => Promise, private previous: CacheState | undefined) { this.query = cacheQuery(this._cacheKey); if (this.previous) { const current = objects.assign({}, this.query, { cacheKey: null }); const previous = objects.assign({}, this.previous.query, { cacheKey: null }); if (!objects.equals(current, previous)) { this.previous.dispose(); - this.previous = null; + this.previous = undefined; } } } @@ -315,7 +315,7 @@ export class CacheState { this.loadingPhase = LoadingPhase.Loaded; if (this.previous) { this.previous.dispose(); - this.previous = null; + this.previous = undefined; } }, err => { this.loadingPhase = LoadingPhase.Errored; @@ -337,7 +337,7 @@ export class CacheState { } if (this.previous) { this.previous.dispose(); - this.previous = null; + this.previous = undefined; } } } diff --git a/src/vs/workbench/contrib/search/browser/patternInputWidget.ts b/src/vs/workbench/contrib/search/browser/patternInputWidget.ts index ab4e731437..c63fe21d82 100644 --- a/src/vs/workbench/contrib/search/browser/patternInputWidget.ts +++ b/src/vs/workbench/contrib/search/browser/patternInputWidget.ts @@ -29,14 +29,14 @@ export class PatternInputWidget extends Widget { static OPTION_CHANGE: string = 'optionChange'; - inputFocusTracker: dom.IFocusTracker; + inputFocusTracker!: dom.IFocusTracker; private width: number; private placeholder: string; private ariaLabel: string; - private domNode: HTMLElement; - protected inputBox: HistoryInputBox; + private domNode!: HTMLElement; + protected inputBox!: HistoryInputBox; private _onSubmit = this._register(new Emitter()); onSubmit: CommonEvent = this._onSubmit.event; @@ -148,7 +148,7 @@ export class PatternInputWidget extends Widget { this.setInputWidth(); } - protected renderSubcontrols(controlsDiv: HTMLDivElement): void { + protected renderSubcontrols(_controlsDiv: HTMLDivElement): void { } private onInputKeyUp(keyboardEvent: IKeyboardEvent) { @@ -174,7 +174,7 @@ export class ExcludePatternInputWidget extends PatternInputWidget { super(parent, contextViewProvider, options, themeService, contextKeyService); } - private useExcludesAndIgnoreFilesBox: Checkbox; + private useExcludesAndIgnoreFilesBox!: Checkbox; dispose(): void { super.dispose(); @@ -209,4 +209,4 @@ export class ExcludePatternInputWidget extends PatternInputWidget { controlsDiv.appendChild(this.useExcludesAndIgnoreFilesBox.domNode); super.renderSubcontrols(controlsDiv); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/search/browser/replaceService.ts b/src/vs/workbench/contrib/search/browser/replaceService.ts index 5488254d36..444d8195c4 100644 --- a/src/vs/workbench/contrib/search/browser/replaceService.ts +++ b/src/vs/workbench/contrib/search/browser/replaceService.ts @@ -91,7 +91,7 @@ class ReplacePreviewModel extends Disposable { export class ReplaceService implements IReplaceService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @ITextFileService private readonly textFileService: ITextFileService, diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 588bb58e9d..2cd398de32 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -274,7 +274,7 @@ MenuRegistry.appendMenuItem(MenuId.SearchContext, { KeybindingsRegistry.registerCommandAndKeybindingRule({ id: Constants.CopyPathCommandId, weight: KeybindingWeight.WorkbenchContrib, - when: Constants.FileMatchOrFolderMatchFocusKey, + when: Constants.FileMatchOrFolderMatchWithResourceFocusKey, primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C, win: { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_C @@ -287,7 +287,7 @@ MenuRegistry.appendMenuItem(MenuId.SearchContext, { id: Constants.CopyPathCommandId, title: nls.localize('copyPathLabel', "Copy Path") }, - when: Constants.FileMatchOrFolderMatchFocusKey, + when: Constants.FileMatchOrFolderMatchWithResourceFocusKey, group: 'search_2', order: 2 }); diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index 9a0b1a25fa..e92897f62e 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -5,7 +5,6 @@ import * as DOM from 'vs/base/browser/dom'; import { Action } from 'vs/base/common/actions'; -import { INavigator } from 'vs/base/common/iterator'; import { createKeybinding, ResolvedKeybinding } from 'vs/base/common/keyCodes'; import { isWindows, OS } from 'vs/base/common/platform'; import { repeat } from 'vs/base/common/strings'; @@ -20,7 +19,7 @@ import { getSelectionKeyboardEvent, WorkbenchObjectTree } from 'vs/platform/list import { SearchView } from 'vs/workbench/contrib/search/browser/searchView'; import * as Constants from 'vs/workbench/contrib/search/common/constants'; import { IReplaceService } from 'vs/workbench/contrib/search/common/replace'; -import { BaseFolderMatch, FileMatch, FileMatchOrMatch, FolderMatch, Match, RenderableMatch, searchMatchComparer, SearchResult } from 'vs/workbench/contrib/search/common/searchModel'; +import { FolderMatch, FileMatch, FileMatchOrMatch, FolderMatchWithResource, Match, RenderableMatch, searchMatchComparer, SearchResult } from 'vs/workbench/contrib/search/common/searchModel'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; @@ -29,6 +28,7 @@ import { ISearchHistoryService } from 'vs/workbench/contrib/search/common/search import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { SearchViewlet } from 'vs/workbench/contrib/search/browser/searchViewlet'; import { SearchPanel } from 'vs/workbench/contrib/search/browser/searchPanel'; +import { ITreeNavigator } from 'vs/base/browser/ui/tree/tree'; export function isSearchViewFocused(viewletService: IViewletService, panelService: IPanelService): boolean { const searchView = getSearchView(viewletService, panelService); @@ -312,7 +312,7 @@ export class CollapseDeepestExpandedLevelAction extends Action { const navigator = viewer.navigate(); let node = navigator.first(); let collapseFileMatchLevel = false; - if (node instanceof BaseFolderMatch) { + if (node instanceof FolderMatch) { while (node = navigator.next()) { if (node instanceof Match) { collapseFileMatchLevel = true; @@ -447,9 +447,9 @@ export abstract class AbstractSearchAndReplaceAction extends Action { } getNextElementAfterRemoved(viewer: WorkbenchObjectTree, element: RenderableMatch): RenderableMatch { - const navigator: INavigator = viewer.navigate(element); - if (element instanceof BaseFolderMatch) { - while (!!navigator.next() && !(navigator.current() instanceof BaseFolderMatch)) { } + const navigator: ITreeNavigator = viewer.navigate(element); + if (element instanceof FolderMatch) { + while (!!navigator.next() && !(navigator.current() instanceof FolderMatch)) { } } else if (element instanceof FileMatch) { while (!!navigator.next() && !(navigator.current() instanceof FileMatch)) { } } else { @@ -461,7 +461,7 @@ export abstract class AbstractSearchAndReplaceAction extends Action { } getPreviousElementAfterRemoved(viewer: WorkbenchObjectTree, element: RenderableMatch): RenderableMatch { - const navigator: INavigator = viewer.navigate(element); + const navigator: ITreeNavigator = viewer.navigate(element); let previousElement = navigator.previous(); // Hence take the previous element. @@ -476,7 +476,7 @@ export abstract class AbstractSearchAndReplaceAction extends Action { // If the previous element is a File or Folder, expand it and go to its last child. // Spell out the two cases, would be too easy to create an infinite loop, like by adding another level... - if (element instanceof Match && previousElement && previousElement instanceof BaseFolderMatch) { + if (element instanceof Match && previousElement && previousElement instanceof FolderMatch) { navigator.next(); viewer.expand(previousElement); previousElement = navigator.previous(); @@ -613,7 +613,7 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction { } private getElementToFocusAfterReplace(): Match { - const navigator: INavigator = this.viewer.navigate(); + const navigator: ITreeNavigator = this.viewer.navigate(); let fileMatched = false; let elementToFocus: any = null; do { @@ -664,7 +664,7 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction { } } -export const copyPathCommand: ICommandHandler = async (accessor, fileMatch: FileMatch | FolderMatch) => { +export const copyPathCommand: ICommandHandler = async (accessor, fileMatch: FileMatch | FolderMatchWithResource) => { const clipboardService = accessor.get(IClipboardService); const labelService = accessor.get(ILabelService); @@ -712,7 +712,7 @@ function fileMatchToString(fileMatch: FileMatch, maxMatches: number, labelServic }; } -function folderMatchToString(folderMatch: FolderMatch | BaseFolderMatch, maxMatches: number, labelService: ILabelService): { text: string, count: number } { +function folderMatchToString(folderMatch: FolderMatchWithResource | FolderMatch, maxMatches: number, labelService: ILabelService): { text: string, count: number } { const fileResults: string[] = []; let numMatches = 0; @@ -740,7 +740,7 @@ export const copyMatchCommand: ICommandHandler = async (accessor, match: Rendera text = matchToString(match); } else if (match instanceof FileMatch) { text = fileMatchToString(match, maxClipboardMatches, labelService).text; - } else if (match instanceof BaseFolderMatch) { + } else if (match instanceof FolderMatch) { text = folderMatchToString(match, maxClipboardMatches, labelService).text; } @@ -749,7 +749,7 @@ export const copyMatchCommand: ICommandHandler = async (accessor, match: Rendera } }; -function allFolderMatchesToString(folderMatches: Array, maxMatches: number, labelService: ILabelService): string { +function allFolderMatchesToString(folderMatches: Array, maxMatches: number, labelService: ILabelService): string { const folderResults: string[] = []; let numMatches = 0; folderMatches = folderMatches.sort(searchMatchComparer); diff --git a/src/vs/workbench/contrib/search/browser/searchResultsView.ts b/src/vs/workbench/contrib/search/browser/searchResultsView.ts index 08b50b6643..ef8561663f 100644 --- a/src/vs/workbench/contrib/search/browser/searchResultsView.ts +++ b/src/vs/workbench/contrib/search/browser/searchResultsView.ts @@ -25,7 +25,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels'; import { RemoveAction, ReplaceAction, ReplaceAllAction, ReplaceAllInFolderAction } from 'vs/workbench/contrib/search/browser/searchActions'; import { SearchView } from 'vs/workbench/contrib/search/browser/searchView'; -import { FileMatch, FolderMatch, Match, RenderableMatch, SearchModel, BaseFolderMatch } from 'vs/workbench/contrib/search/common/searchModel'; +import { FileMatch, Match, RenderableMatch, SearchModel, FolderMatch } from 'vs/workbench/contrib/search/common/searchModel'; import { IDragAndDropData } from 'vs/base/browser/dnd'; import { fillResourceDataTransfers } from 'vs/workbench/browser/dnd'; import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; @@ -63,7 +63,7 @@ export class SearchDelegate implements IListVirtualDelegate { } getTemplateId(element: RenderableMatch): string { - if (element instanceof BaseFolderMatch) { + if (element instanceof FolderMatch) { return FolderMatchRenderer.TEMPLATE_ID; } else if (element instanceof FileMatch) { return FileMatchRenderer.TEMPLATE_ID; @@ -114,7 +114,7 @@ export class FolderMatchRenderer extends Disposable implements ITreeRenderer, index: number, templateData: IFolderMatchTemplate): void { const folderMatch = node.element; - if (folderMatch.hasResource()) { + if (folderMatch.resource) { 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 }); @@ -309,8 +309,8 @@ export class SearchAccessibilityProvider implements IAccessibilityProvider; private fileMatchOrMatchFocused: IContextKey; private fileMatchOrFolderMatchFocus: IContextKey; + private fileMatchOrFolderMatchWithResourceFocus: IContextKey; private fileMatchFocused: IContextKey; private folderMatchFocused: IContextKey; private matchFocused: IContextKey; private hasSearchResultsKey: IContextKey; - private state: SearchUIState; + private state: SearchUIState = SearchUIState.Idle; private actions: Array = []; private cancelAction: CancelSearchAction; private refreshAction: RefreshAction; - private contextMenu: IMenu; + private contextMenu: IMenu | null = null; - private tree: WorkbenchObjectTree; - private treeLabels: ResourceLabels; + private tree!: WorkbenchObjectTree; + private treeLabels!: ResourceLabels; private viewletState: MementoObject; - private globalMemento: MementoObject; - private messagesElement: HTMLElement; + private messagesElement!: HTMLElement; private messageDisposables: IDisposable[] = []; - private searchWidgetsContainerElement: HTMLElement; - private searchWidget: SearchWidget; - private size: dom.Dimension; - private queryDetails: HTMLElement; - private toggleQueryDetailsButton: HTMLElement; - private inputPatternExcludes: ExcludePatternInputWidget; - private inputPatternIncludes: PatternInputWidget; - private resultsElement: HTMLElement; + private searchWidgetsContainerElement!: HTMLElement; + private searchWidget!: SearchWidget; + private size!: dom.Dimension; + private queryDetails!: HTMLElement; + private toggleQueryDetailsButton!: HTMLElement; + private inputPatternExcludes!: ExcludePatternInputWidget; + private inputPatternIncludes!: PatternInputWidget; + private resultsElement!: HTMLElement; private currentSelectedFileMatch: FileMatch | undefined; private delayedRefresh: Delayer; - private changedWhileHidden: boolean; + private changedWhileHidden: boolean = false; private searchWithoutFolderMessageElement: HTMLElement | undefined; @@ -164,6 +164,7 @@ export class SearchView extends ViewletPanel { this.firstMatchFocused = Constants.FirstMatchFocusKey.bindTo(contextKeyService); this.fileMatchOrMatchFocused = Constants.FileMatchOrMatchFocusKey.bindTo(contextKeyService); this.fileMatchOrFolderMatchFocus = Constants.FileMatchOrFolderMatchFocusKey.bindTo(contextKeyService); + this.fileMatchOrFolderMatchWithResourceFocus = Constants.FileMatchOrFolderMatchWithResourceFocusKey.bindTo(contextKeyService); this.fileMatchFocused = Constants.FileFocusKey.bindTo(contextKeyService); this.folderMatchFocused = Constants.FolderFocusKey.bindTo(contextKeyService); this.matchFocused = Constants.MatchFocusKey.bindTo(this.contextKeyService); @@ -173,7 +174,6 @@ export class SearchView extends ViewletPanel { this.queryBuilder = this.instantiationService.createInstance(QueryBuilder); this.memento = new Memento(this.id, storageService); this.viewletState = this.memento.getMemento(StorageScope.WORKSPACE); - this.globalMemento = this.memento.getMemento(StorageScope.GLOBAL); this._register(this.fileService.onFileChanges(e => this.onFilesChanged(e))); this._register(this.untitledEditorService.onDidChangeDirty(e => this.onUntitledDidChangeDirty(e))); @@ -441,28 +441,20 @@ export class SearchView extends ViewletPanel { private refreshAndUpdateCount(event?: IChangeEvent): void { this.searchWidget.setReplaceAllActionState(!this.viewModel.searchResult.isEmpty()); - this.updateSearchResultCount(this.viewModel.searchResult.query.userDisabledExcludesAndIgnoreFiles); + this.updateSearchResultCount(this.viewModel.searchResult.query!.userDisabledExcludesAndIgnoreFiles); return this.refreshTree(event); } refreshTree(event?: IChangeEvent): void { const collapseResults = this.configurationService.getValue('search').collapseResults; if (!event || event.added || event.removed) { + // Refresh whole tree this.tree.setChildren(null, this.createResultIterator(collapseResults)); } else { + // FileMatch modified, refresh those elements event.elements.forEach(element => { - if (element instanceof BaseFolderMatch) { - // The folder may or may not be in the tree. Refresh the whole thing. - this.tree.setChildren(null, this.createResultIterator(collapseResults)); - return; - } - - if (element instanceof SearchResult) { - this.tree.setChildren(null, this.createIterator(element, collapseResults)); - } else { - this.tree.setChildren(element, this.createIterator(element, collapseResults)); - this.tree.rerender(element); - } + this.tree.setChildren(element, this.createIterator(element, collapseResults)); + this.tree.rerender(element); }); } } @@ -483,7 +475,7 @@ export class SearchView extends ViewletPanel { }); } - private createFolderIterator(folderMatch: BaseFolderMatch, collapseResults: ISearchConfigurationProperties['collapseResults']): Iterator> { + private createFolderIterator(folderMatch: FolderMatch, collapseResults: ISearchConfigurationProperties['collapseResults']): Iterator> { const filesIt = Iterator.fromArray( folderMatch.matches() .sort(searchMatchComparer)); @@ -508,9 +500,9 @@ export class SearchView extends ViewletPanel { return Iterator.map(matchesIt, r => (>{ element: r })); } - private createIterator(match: BaseFolderMatch | FileMatch | SearchResult, collapseResults: ISearchConfigurationProperties['collapseResults']): Iterator> { + private createIterator(match: FolderMatch | FileMatch | SearchResult, collapseResults: ISearchConfigurationProperties['collapseResults']): Iterator> { return match instanceof SearchResult ? this.createResultIterator(collapseResults) : - match instanceof BaseFolderMatch ? this.createFolderIterator(match, collapseResults) : + match instanceof FolderMatch ? this.createFolderIterator(match, collapseResults) : this.createFileIterator(match); } @@ -642,6 +634,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, + 'SearchView', this.resultsElement, delegate, [ @@ -680,6 +673,7 @@ export class SearchView extends ViewletPanel { this.folderMatchFocused.set(focus instanceof FolderMatch); this.matchFocused.set(focus instanceof Match); this.fileMatchOrFolderMatchFocus.set(focus instanceof FileMatch || focus instanceof FolderMatch); + this.fileMatchOrFolderMatchWithResourceFocus.set(focus instanceof FileMatch || focus instanceof FolderMatchWithResource); } })); @@ -690,6 +684,7 @@ export class SearchView extends ViewletPanel { this.folderMatchFocused.reset(); this.matchFocused.reset(); this.fileMatchOrFolderMatchFocus.reset(); + this.fileMatchOrFolderMatchWithResourceFocus.reset(); })); } @@ -716,7 +711,7 @@ export class SearchView extends ViewletPanel { const [selected] = this.tree.getSelection(); // Expand the initial selected node, if needed - if (selected instanceof FileMatch) { + if (selected && !(selected instanceof Match)) { if (this.tree.isCollapsed(selected)) { this.tree.expand(selected); } @@ -726,23 +721,24 @@ export class SearchView extends ViewletPanel { let next = navigator.next(); if (!next) { - // Reached the end - get a new navigator from the root. - navigator = this.tree.navigate(); next = navigator.first(); } - // Expand and go past FileMatch nodes + // Expand until first child is a Match while (!(next instanceof Match)) { if (this.tree.isCollapsed(next)) { this.tree.expand(next); } - // Select the FileMatch's first child + // Select the first child next = navigator.next(); } // Reveal the newly selected element if (next) { + if (next === selected) { + this.tree.setFocus([]); + } this.tree.setFocus([next], getSelectionKeyboardEvent(undefined, false)); this.tree.reveal(next); } @@ -754,34 +750,24 @@ export class SearchView extends ViewletPanel { let prev = navigator.previous(); - // Expand and go past FileMatch nodes - if (!(prev instanceof Match)) { - prev = navigator.previous(); - if (!prev) { - // Wrap around - prev = navigator.last(); + // Select previous until find a Match or a collapsed item + while (!prev || (!(prev instanceof Match) && !this.tree.isCollapsed(prev))) { + prev = prev ? navigator.previous() : navigator.last(); + } - // This is complicated because .last will set the navigator to the last FileMatch, - // so expand it and FF to its last child - this.tree.expand(prev); - let tmp: RenderableMatch | null; - while (tmp = navigator.next()) { - prev = tmp; - } - } - - if (!(prev instanceof Match)) { - // There is a second non-Match result, which must be a collapsed FileMatch. - // Expand it then select its last child. - const nextItem = navigator.next(); - this.tree.expand(prev); - navigator = this.tree.navigate(nextItem); // recreate navigator because modifying the tree can invalidate it - prev = navigator.previous(); - } + // Expand until last child is a Match + while (!(prev instanceof Match)) { + const nextItem = navigator.next(); + this.tree.expand(prev); + navigator = this.tree.navigate(nextItem); // recreate navigator because modifying the tree can invalidate it + prev = nextItem ? navigator.previous() : navigator.last(); // select last child } // Reveal the newly selected element if (prev) { + if (prev === selected) { + this.tree.setFocus([]); + } this.tree.setFocus([prev], getSelectionKeyboardEvent(undefined, false)); this.tree.reveal(prev); } @@ -1237,7 +1223,7 @@ export class SearchView extends ViewletPanel { return this.fileService.exists(fq.folder); }); - return Promise.resolve(folderQueriesExistP).then(existResults => { + return Promise.all(folderQueriesExistP).then(existResults => { // If no folders exist, show an error message about the first one const existingFolderQueries = query.folderQueries.filter((folderQuery, i) => existResults[i]); if (!query.folderQueries.length || existingFolderQueries.length) { @@ -1383,10 +1369,6 @@ export class SearchView extends ViewletPanel { this.searchWidget.searchInput.showMessage({ content: e.message, type: MessageType.ERROR }); this.viewModel.searchResult.clear(); - if (e.code === SearchErrorCode.regexParseError && !this.configurationService.getValue('search.usePCRE2')) { - this.showPcre2Hint(); - } - return Promise.resolve(); } }; @@ -1421,23 +1403,6 @@ export class SearchView extends ViewletPanel { .then(onComplete, onError); } - private showPcre2Hint(): void { - if (!this.globalMemento['disablePcre2Hint']) { - // If the regex parsed in JS but not rg, it likely uses features that are supported in JS and PCRE2 but not Rust - this.notificationService.prompt(Severity.Info, nls.localize('rgRegexError', "You can enable \"search.usePCRE2\" to enable some extra regex features like lookbehind and backreferences."), [ - { - label: nls.localize('neverAgain', "Don't Show Again"), - run: () => this.globalMemento['disablePcre2Hint'] = true, - isSecondary: true - }, - { - label: nls.localize('otherEncodingWarning.openSettingsLabel', "Open Settings"), - run: () => this.openSettings('search.usePCRE2') - } - ]); - } - } - private addClickEvents = (element: HTMLElement, handler: (event: any) => void): void => { this.messageDisposables.push(dom.addDisposableListener(element, dom.EventType.CLICK, handler)); this.messageDisposables.push(dom.addDisposableListener(element, dom.EventType.KEY_DOWN, e => { diff --git a/src/vs/workbench/contrib/search/browser/searchWidget.ts b/src/vs/workbench/contrib/search/browser/searchWidget.ts index 55a35a9896..5bef9b769f 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -34,6 +34,7 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox'; +import { isMacintosh } from 'vs/base/common/platform'; export interface ISearchWidgetOptions { value?: string; @@ -58,7 +59,7 @@ class ReplaceAllAction extends Action { return ReplaceAllAction.fgInstance; } - private _searchWidget: SearchWidget; + private _searchWidget: SearchWidget | null = null; constructor() { super(ReplaceAllAction.ID, '', 'action-replace-all', false); @@ -76,6 +77,8 @@ class ReplaceAllAction extends Action { } } +const ctrlKeyMod = (isMacintosh ? KeyMod.WinCtrl : KeyMod.CtrlCmd); + export class SearchWidget extends Widget { private static readonly REPLACE_ALL_DISABLED_LABEL = nls.localize('search.action.replaceAll.disabled.label', "Replace All (Submit Search to Enable)"); @@ -84,25 +87,25 @@ export class SearchWidget extends Widget { return appendKeyBindingLabel(nls.localize('search.action.replaceAll.enabled.label', "Replace All"), kb, keyBindingService2); } - domNode: HTMLElement; + domNode!: HTMLElement; - searchInput: FindInput; - searchInputFocusTracker: dom.IFocusTracker; + searchInput!: FindInput; + searchInputFocusTracker!: dom.IFocusTracker; private searchInputBoxFocused: IContextKey; - private replaceContainer: HTMLElement; - replaceInput: HistoryInputBox; - private toggleReplaceButton: Button; - private replaceAllAction: ReplaceAllAction; + private replaceContainer!: HTMLElement; + replaceInput!: HistoryInputBox; + private toggleReplaceButton!: Button; + private replaceAllAction!: ReplaceAllAction; private replaceActive: IContextKey; - private replaceActionBar: ActionBar; - replaceInputFocusTracker: dom.IFocusTracker; + private replaceActionBar!: ActionBar; + replaceInputFocusTracker!: dom.IFocusTracker; private replaceInputBoxFocused: IContextKey; private _replaceHistoryDelayer: Delayer; - private _preserveCase: Checkbox; + private _preserveCase!: Checkbox; private ignoreGlobalFindBufferOnNextFocus = false; - private previousGlobalFindBufferValue: string; + private previousGlobalFindBufferValue: string | null = null; private _onSearchSubmit = this._register(new Emitter()); readonly onSearchSubmit: Event = this._onSearchSubmit.event; @@ -426,7 +429,7 @@ export class SearchWidget extends Widget { } try { // tslint:disable-next-line: no-unused-expression - new RegExp(value); + new RegExp(value, 'u'); } catch (e) { return { content: e.message }; } @@ -446,6 +449,11 @@ export class SearchWidget extends Widget { } private onSearchInputKeyDown(keyboardEvent: IKeyboardEvent) { + if (keyboardEvent.equals(ctrlKeyMod | KeyCode.Enter)) { + this.searchInput.inputBox.insertAtCursor('\n'); + keyboardEvent.preventDefault(); + } + if (keyboardEvent.equals(KeyCode.Enter)) { this.submitSearch(); keyboardEvent.preventDefault(); @@ -503,6 +511,11 @@ export class SearchWidget extends Widget { } private onReplaceInputKeyDown(keyboardEvent: IKeyboardEvent) { + if (keyboardEvent.equals(ctrlKeyMod | KeyCode.Enter)) { + this.searchInput.inputBox.insertAtCursor('\n'); + keyboardEvent.preventDefault(); + } + if (keyboardEvent.equals(KeyCode.Enter)) { this.submitSearch(); keyboardEvent.preventDefault(); diff --git a/src/vs/workbench/contrib/search/common/constants.ts b/src/vs/workbench/contrib/search/common/constants.ts index 95b3dd5005..cde331349c 100644 --- a/src/vs/workbench/contrib/search/common/constants.ts +++ b/src/vs/workbench/contrib/search/common/constants.ts @@ -41,6 +41,7 @@ export const HasSearchResults = new RawContextKey('hasSearchResult', fa export const FirstMatchFocusKey = new RawContextKey('firstMatchFocus', false); export const FileMatchOrMatchFocusKey = new RawContextKey('fileMatchOrMatchFocus', false); // This is actually, Match or File or Folder export const FileMatchOrFolderMatchFocusKey = new RawContextKey('fileMatchOrFolderMatchFocus', false); +export const FileMatchOrFolderMatchWithResourceFocusKey = new RawContextKey('fileMatchOrFolderMatchWithResourceFocus', false); // Excludes "Other files" export const FileFocusKey = new RawContextKey('fileMatchFocus', false); export const FolderFocusKey = new RawContextKey('folderMatchFocus', false); export const MatchFocusKey = new RawContextKey('matchFocus', false); diff --git a/src/vs/workbench/contrib/search/common/replace.ts b/src/vs/workbench/contrib/search/common/replace.ts index 3154f41ab6..99cc2e1090 100644 --- a/src/vs/workbench/contrib/search/common/replace.ts +++ b/src/vs/workbench/contrib/search/common/replace.ts @@ -11,7 +11,7 @@ export const IReplaceService = createDecorator('replaceService' export interface IReplaceService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Replaces the given match in the file that match belongs to diff --git a/src/vs/workbench/contrib/search/common/searchHistoryService.ts b/src/vs/workbench/contrib/search/common/searchHistoryService.ts index 5e6334caec..aac13dafc8 100644 --- a/src/vs/workbench/contrib/search/common/searchHistoryService.ts +++ b/src/vs/workbench/contrib/search/common/searchHistoryService.ts @@ -9,7 +9,7 @@ import { isEmptyObject } from 'vs/base/common/types'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export interface ISearchHistoryService { - _serviceBrand: any; + _serviceBrand: undefined; onDidClearHistory: Event; clearHistory(): void; load(): ISearchHistoryValues; @@ -26,7 +26,7 @@ export interface ISearchHistoryValues { } export class SearchHistoryService implements ISearchHistoryService { - _serviceBrand: any; + _serviceBrand: undefined; private static readonly SEARCH_HISTORY_KEY = 'workbench.search.history'; diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index b86038edbe..a1d28e658a 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -188,16 +188,16 @@ export class FileMatch extends Disposable implements IFileMatch { readonly onDispose: Event = this._onDispose.event; private _resource: URI; - private _model: ITextModel | null; - private _modelListener: IDisposable; + private _model: ITextModel | null = null; + private _modelListener: IDisposable | null = null; private _matches: Map; private _removedMatches: Set; - private _selectedMatch: Match | null; + private _selectedMatch: Match | null = null; private _updateScheduler: RunOnceScheduler; private _modelDecorations: string[] = []; - constructor(private _query: IPatternInfo, private _previewOptions: ITextSearchPreviewOptions, private _maxResults: number, private _parent: BaseFolderMatch, private rawMatch: IFileMatch, + constructor(private _query: IPatternInfo, private _previewOptions: ITextSearchPreviewOptions, private _maxResults: number, private _parent: FolderMatch, private rawMatch: IFileMatch, @IModelService private readonly modelService: IModelService, @IReplaceService private readonly replaceService: IReplaceService ) { super(); @@ -244,7 +244,7 @@ export class FileMatch extends Disposable implements IFileMatch { this._updateScheduler.cancel(); this._model.deltaDecorations(this._modelDecorations, []); this._model = null; - this._modelListener.dispose(); + this._modelListener!.dispose(); } } @@ -322,7 +322,7 @@ export class FileMatch extends Disposable implements IFileMatch { return this.resource.toString(); } - parent(): BaseFolderMatch { + parent(): FolderMatch { return this._parent; } @@ -400,12 +400,12 @@ export class FileMatch extends Disposable implements IFileMatch { } export interface IChangeEvent { - elements: (FileMatch | FolderMatch | SearchResult)[]; + elements: FileMatch[]; added?: boolean; removed?: boolean; } -export class BaseFolderMatch extends Disposable { +export class FolderMatch extends Disposable { private _onChange = this._register(new Emitter()); readonly onChange: Event = this._onChange.event; @@ -458,10 +458,6 @@ export class BaseFolderMatch extends Disposable { return this._parent; } - hasResource(): boolean { - return !!this._resource; - } - bindModel(model: ITextModel): void { const fileMatch = this._fileMatches.get(model.uri); if (fileMatch) { @@ -598,7 +594,7 @@ export class BaseFolderMatch extends Disposable { * BaseFolderMatch => optional resource ("other files" node) * FolderMatch => required resource (normal folder node) */ -export class FolderMatch extends BaseFolderMatch { +export class FolderMatchWithResource extends FolderMatch { constructor(_resource: URI, _id: string, _index: number, _query: ITextQuery, _parent: SearchResult, _searchModel: SearchModel, @IReplaceService replaceService: IReplaceService, @IInstantiationService instantiationService: IInstantiationService @@ -616,7 +612,7 @@ export class FolderMatch extends BaseFolderMatch { * and their sort order is undefined. */ export function searchMatchComparer(elementA: RenderableMatch, elementB: RenderableMatch): number { - if (elementA instanceof BaseFolderMatch && elementB instanceof BaseFolderMatch) { + if (elementA instanceof FolderMatch && elementB instanceof FolderMatch) { return elementA.index() - elementB.index(); } @@ -636,11 +632,11 @@ export class SearchResult extends Disposable { private _onChange = this._register(new Emitter()); readonly onChange: Event = this._onChange.event; - private _folderMatches: FolderMatch[] = []; - private _otherFilesMatch: BaseFolderMatch; - private _folderMatchesMap: TernarySearchTree = TernarySearchTree.forPaths(); - private _showHighlights: boolean; - private _query: ITextQuery; + private _folderMatches: FolderMatchWithResource[] = []; + private _otherFilesMatch: FolderMatch | null = null; + private _folderMatchesMap: TernarySearchTree = TernarySearchTree.forPaths(); + private _showHighlights: boolean = false; + private _query: ITextQuery | null = null; private _rangeHighlightDecorations: RangeHighlightDecorations; @@ -657,16 +653,20 @@ export class SearchResult extends Disposable { this._register(this.modelService.onModelAdded(model => this.onModelAdded(model))); } - get query(): ITextQuery { + get query(): ITextQuery | null { return this._query; } - set query(query: ITextQuery) { + set query(query: ITextQuery | null) { // When updating the query we could change the roots, so ensure we clean up the old roots first. this.clear(); - this._folderMatches = (query.folderQueries || []) + if (!query) { + return; + } + + this._folderMatches = (query && query.folderQueries || []) .map(fq => fq.folder) - .map((resource, index) => this.createFolderMatch(resource, resource.toString(), index, query)); + .map((resource, index) => this.createFolderMatchWithResource(resource, resource.toString(), index, query)); this._folderMatches.forEach(fm => this._folderMatchesMap.set(fm.resource.toString(), fm)); this._otherFilesMatch = this.createOtherFilesFolderMatch('otherFiles', this._folderMatches.length + 1, query); @@ -681,15 +681,15 @@ export class SearchResult extends Disposable { } } - private createFolderMatch(resource: URI, id: string, index: number, query: ITextQuery): FolderMatch { - return this._createBaseFolderMatch(FolderMatch, resource, id, index, query); + private createFolderMatchWithResource(resource: URI, id: string, index: number, query: ITextQuery): FolderMatchWithResource { + return this._createBaseFolderMatch(FolderMatchWithResource, resource, id, index, query); } - private createOtherFilesFolderMatch(id: string, index: number, query: ITextQuery): BaseFolderMatch { - return this._createBaseFolderMatch(BaseFolderMatch, null, id, index, query); + private createOtherFilesFolderMatch(id: string, index: number, query: ITextQuery): FolderMatch { + return this._createBaseFolderMatch(FolderMatch, null, id, index, query); } - private _createBaseFolderMatch(folderMatchClass: typeof BaseFolderMatch | typeof FolderMatch, resource: URI | null, id: string, index: number, query: ITextQuery): BaseFolderMatch { + private _createBaseFolderMatch(folderMatchClass: typeof FolderMatch | typeof FolderMatchWithResource, resource: URI | null, id: string, index: number, query: ITextQuery): FolderMatch { const folderMatch = this.instantiationService.createInstance(folderMatchClass, resource, id, index, query, this, this._searchModel); const disposable = folderMatch.onChange((event) => this._onChange.fire(event)); folderMatch.onDispose(() => disposable.dispose()); @@ -721,6 +721,8 @@ export class SearchResult extends Disposable { clear(): void { this.folderMatches().forEach((folderMatch) => folderMatch.clear()); this.disposeMatches(); + this._folderMatches = []; + this._otherFilesMatch = null; } remove(matches: FileMatch | FolderMatch | (FileMatch | FolderMatch)[]): void { @@ -734,9 +736,9 @@ export class SearchResult extends Disposable { } }); - matches = matches.filter(m => m instanceof FileMatch); + const fileMatches: FileMatch[] = matches.filter(m => m instanceof FileMatch) as FileMatch[]; - const { byFolder, other } = this.groupFilesByFolder(matches); + const { byFolder, other } = this.groupFilesByFolder(fileMatches); byFolder.forEach(matches => { if (!matches.length) { return; @@ -774,7 +776,7 @@ export class SearchResult extends Disposable { }); } - folderMatches(): BaseFolderMatch[] { + folderMatches(): FolderMatch[] { return this._otherFilesMatch ? [ ...this._folderMatches, @@ -837,9 +839,9 @@ export class SearchResult extends Disposable { return this._rangeHighlightDecorations; } - private getFolderMatch(resource: URI): BaseFolderMatch { + private getFolderMatch(resource: URI): FolderMatch { const folderMatch = this._folderMatchesMap.findSubstr(resource.toString()); - return folderMatch ? folderMatch : this._otherFilesMatch; + return folderMatch ? folderMatch : this._otherFilesMatch!; } private set replacingAll(running: boolean) { @@ -877,7 +879,7 @@ export class SearchResult extends Disposable { private disposeMatches(): void { this.folderMatches().forEach(folderMatch => folderMatch.dispose()); this._folderMatches = []; - this._folderMatchesMap = TernarySearchTree.forPaths(); + this._folderMatchesMap = TernarySearchTree.forPaths(); this._rangeHighlightDecorations.removeHighlightRange(); } @@ -900,7 +902,7 @@ export class SearchModel extends Disposable { private readonly _onReplaceTermChanged: Emitter = this._register(new Emitter()); readonly onReplaceTermChanged: Event = this._onReplaceTermChanged.event; - private currentCancelTokenSource: CancellationTokenSource; + private currentCancelTokenSource: CancellationTokenSource | null = null; constructor( @ISearchService private readonly searchService: ISearchService, @@ -980,21 +982,19 @@ export class SearchModel extends Disposable { */ onFirstRenderStopwatch(duration => this.telemetryService.publicLog('searchResultsFirstRender', { duration })); - const onDoneStopwatch = Event.stopwatch(onDone); const start = Date.now(); - - /* __GDPR__ - "searchResultsFinished" : { - "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true } - } - */ - onDoneStopwatch(duration => this.telemetryService.publicLog('searchResultsFinished', { duration })); - currentRequest.then( value => this.onSearchCompleted(value, Date.now() - start), e => this.onSearchError(e, Date.now() - start)); - return currentRequest; + return currentRequest.finally(() => { + /* __GDPR__ + "searchResultsFinished" : { + "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true } + } + */ + this.telemetryService.publicLog('searchResultsFinished', { duration: Date.now() - start }); + }); } private onSearchCompleted(completed: ISearchComplete | null, duration: number): ISearchComplete | null { @@ -1063,12 +1063,12 @@ export class SearchModel extends Disposable { export type FileMatchOrMatch = FileMatch | Match; -export type RenderableMatch = BaseFolderMatch | FolderMatch | FileMatch | Match; +export type RenderableMatch = FolderMatch | FolderMatchWithResource | FileMatch | Match; export class SearchWorkbenchService implements ISearchWorkbenchService { - _serviceBrand: any; - private _searchModel: SearchModel; + _serviceBrand: undefined; + private _searchModel: SearchModel | null = null; constructor(@IInstantiationService private readonly instantiationService: IInstantiationService) { } @@ -1084,7 +1084,7 @@ export class SearchWorkbenchService implements ISearchWorkbenchService { export const ISearchWorkbenchService = createDecorator('searchWorkbenchService'); export interface ISearchWorkbenchService { - _serviceBrand: any; + _serviceBrand: undefined; readonly searchModel: SearchModel; } diff --git a/src/vs/workbench/contrib/search/test/browser/mockSearchTree.ts b/src/vs/workbench/contrib/search/test/browser/mockSearchTree.ts index f205f69733..80e69d667a 100644 --- a/src/vs/workbench/contrib/search/test/browser/mockSearchTree.ts +++ b/src/vs/workbench/contrib/search/test/browser/mockSearchTree.ts @@ -68,10 +68,6 @@ class ArrayNavigator implements ITreeNavigator { return this.elements[--this.index]; } - parent(): T | null { - throw new Error('not implemented'); - } - first(): T | null { this.index = 0; return this.elements[this.index]; 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 c87c159415..0950afa2d7 100644 --- a/src/vs/workbench/contrib/search/test/common/searchModel.test.ts +++ b/src/vs/workbench/contrib/search/test/common/searchModel.test.ts @@ -21,14 +21,14 @@ import { SearchModel } from 'vs/workbench/contrib/search/common/searchModel'; import * as process from 'vs/base/common/process'; const nullEvent = new class { - id: number; - topic: string; - name: string; - description: string; + id: number = -1; + topic!: string; + name!: string; + description!: string; data: any; - startTime: Date; - stopTime: Date; + startTime!: Date; + stopTime!: Date; stop(): void { return; diff --git a/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts b/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts index b1a44831b9..29eb6077b4 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts @@ -15,7 +15,7 @@ export const ISnippetsService = createDecorator('snippetServic export interface ISnippetsService { - _serviceBrand: any; + _serviceBrand: undefined; getSnippetFiles(): Promise; @@ -28,6 +28,7 @@ const languageScopeSchemaId = 'vscode://schemas/snippets'; const languageScopeSchema: IJSONSchema = { id: languageScopeSchemaId, allowComments: true, + allowsTrailingCommas: true, defaultSnippets: [{ label: nls.localize('snippetSchema.json.default', "Empty snippet"), body: { '${1:snippetName}': { 'prefix': '${2:prefix}', 'body': '${3:snippet}', 'description': '${4:description}' } } @@ -63,6 +64,7 @@ const globalSchemaId = 'vscode://schemas/global-snippets'; const globalSchema: IJSONSchema = { id: globalSchemaId, allowComments: true, + allowsTrailingCommas: true, defaultSnippets: [{ label: nls.localize('snippetSchema.json.default', "Empty snippet"), body: { '${1:snippetName}': { 'scope': '${2:scope}', 'prefix': '${3:prefix}', 'body': '${4:snippet}', 'description': '${5:description}' } } diff --git a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts index 12d85d8225..316efe6b2b 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts @@ -127,7 +127,7 @@ function watch(service: IFileService, resource: URI, callback: (type: FileChange class SnippetsService implements ISnippetsService { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; private readonly _disposables = new DisposableStore(); private readonly _pendingWork: Promise[] = []; diff --git a/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts b/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts index 71f884b8be..b85ae30b42 100644 --- a/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts +++ b/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts @@ -19,6 +19,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Snippet } from './snippetsFile'; import { SnippetCompletion } from './snippetCompletionProvider'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class TabCompletionController implements editorCommon.IEditorContribution { @@ -42,7 +43,7 @@ export class TabCompletionController implements editorCommon.IEditorContribution ) { this._hasSnippets = TabCompletionController.ContextKey.bindTo(contextKeyService); this._configListener = this._editor.onDidChangeConfiguration(e => { - if (e.contribInfo) { + if (e.hasChanged(EditorOption.tabCompletion)) { this._update(); } }); @@ -59,7 +60,7 @@ export class TabCompletionController implements editorCommon.IEditorContribution } private _update(): void { - const enabled = this._editor.getConfiguration().contribInfo.tabCompletion === 'onlySnippets'; + const enabled = this._editor.getOption(EditorOption.tabCompletion) === 'onlySnippets'; if (this._enabled !== enabled) { this._enabled = enabled; if (!this._enabled) { diff --git a/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts b/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts index 3e08000710..96f5776668 100644 --- a/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts +++ b/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts @@ -15,7 +15,7 @@ import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageCo import { CompletionContext, CompletionTriggerKind } from 'vs/editor/common/modes'; class SimpleSnippetService implements ISnippetsService { - _serviceBrand: any; + _serviceBrand: undefined; constructor(readonly snippets: Snippet[]) { } getSnippets() { diff --git a/src/vs/workbench/contrib/stats/browser/workspaceStatsService.ts b/src/vs/workbench/contrib/stats/browser/workspaceStatsService.ts new file mode 100644 index 0000000000..c9683a14c0 --- /dev/null +++ b/src/vs/workbench/contrib/stats/browser/workspaceStatsService.ts @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace'; +import { URI } from 'vs/base/common/uri'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/common/workspaceStats'; + +export class NoOpWorkspaceStatsService implements IWorkspaceStatsService { + + _serviceBrand: undefined; + + getTags(): Promise { + return Promise.resolve({}); + } + + getTelemetryWorkspaceId(workspace: IWorkspace, state: WorkbenchState): string | undefined { + return undefined; + } + + getHashedRemotesFromUri(workspaceUri: URI, stripEndingDotGit?: boolean): Promise { + return Promise.resolve([]); + } +} + +registerSingleton(IWorkspaceStatsService, NoOpWorkspaceStatsService, true); diff --git a/src/vs/workbench/contrib/stats/common/workspaceStats.ts b/src/vs/workbench/contrib/stats/common/workspaceStats.ts index 6b7016863e..d03a5895b2 100644 --- a/src/vs/workbench/contrib/stats/common/workspaceStats.ts +++ b/src/vs/workbench/contrib/stats/common/workspaceStats.ts @@ -12,7 +12,7 @@ export type Tags = { [index: string]: boolean | number | string | undefined }; export const IWorkspaceStatsService = createDecorator('workspaceStatsService'); export interface IWorkspaceStatsService { - _serviceBrand: any; + _serviceBrand: undefined; getTags(): Promise; diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts index e0266b250e..17c2973c7e 100644 --- a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts +++ b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts @@ -90,8 +90,8 @@ const PyModulesToLookFor = [ ]; export class WorkspaceStatsService implements IWorkspaceStatsService { - _serviceBrand: any; - private _tags: Tags; + _serviceBrand: undefined; + private _tags: Tags | undefined; constructor( @IFileService private readonly fileService: IFileService, diff --git a/src/vs/workbench/contrib/surveys/electron-browser/languageSurveys.contribution.ts b/src/vs/workbench/contrib/surveys/electron-browser/languageSurveys.contribution.ts index 4deb6a0173..832bef10b5 100644 --- a/src/vs/workbench/contrib/surveys/electron-browser/languageSurveys.contribution.ts +++ b/src/vs/workbench/contrib/surveys/electron-browser/languageSurveys.contribution.ts @@ -132,7 +132,7 @@ class LanguageSurveysContribution implements IWorkbenchContribution { @ITextFileService textFileService: ITextFileService, @IOpenerService openerService: IOpenerService ) { - product.surveys + product.surveys! .filter(surveyData => surveyData.surveyId && surveyData.editCount && surveyData.languageId && surveyData.surveyUrl && surveyData.userProbability) .map(surveyData => new LanguageSurvey(surveyData, storageService, notificationService, telemetryService, modelService, textFileService, openerService)); } diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 99e22327d8..251e891414 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -49,7 +49,7 @@ import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/p import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IOutputService, IOutputChannel } from 'vs/workbench/contrib/output/common/output'; -import { ITerminalService } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService, ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { ITaskSystem, ITaskResolver, ITaskSummary, TaskExecuteKind, TaskError, TaskErrors, TaskTerminateResponse, TaskSystemInfo, ITaskExecuteResult } from 'vs/workbench/contrib/tasks/common/taskSystem'; import { @@ -71,7 +71,6 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c import { RunAutomaticTasks } from 'vs/workbench/contrib/tasks/browser/runAutomaticTasks'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { format } from 'vs/base/common/jsonFormatter'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; @@ -173,7 +172,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer private static readonly IgnoreTask010DonotShowAgain_key = 'workbench.tasks.ignoreTask010Shown'; private static CustomizationTelemetryEventName: string = 'taskService.customize'; - public _serviceBrand: any; + public _serviceBrand: undefined; public static OutputChannelId: string = 'tasks'; public static OutputChannelLabel: string = nls.localize('tasks', "Tasks"); @@ -278,6 +277,28 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this._register(lifecycleService.onBeforeShutdown(event => event.veto(this.beforeShutdown()))); this._onDidStateChange = this._register(new Emitter()); this.registerCommands(); + this.configurationResolverService.contributeVariable('defaultBuildTask', async (): Promise => { + let tasks = await this.getTasksForGroup(TaskGroup.Build); + if (tasks.length > 0) { + let { defaults, users } = this.splitPerGroupType(tasks); + if (defaults.length === 1) { + return defaults[0]._label; + } else if (defaults.length + users.length > 0) { + tasks = defaults.concat(users); + } + } + + let entry: TaskQuickPickEntry | null | undefined; + if (tasks && tasks.length > 0) { + entry = await this.showQuickPick(tasks, nls.localize('TaskService.pickBuildTaskForLabel', 'Select the build task')); + } + + let task: Task | undefined | null = entry ? entry.task : undefined; + if (!task) { + return undefined; + } + return task._label; + }); } public get onDidStateChange(): Event { @@ -1723,18 +1744,18 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } return entries; }), { - placeHolder, - matchOnDescription: true, - onDidTriggerItemButton: context => { - let task = context.item.task; - this.quickInputService.cancel(); - if (ContributedTask.is(task)) { - this.customize(task, undefined, true); - } else if (CustomTask.is(task)) { - this.openConfig(task); - } + placeHolder, + matchOnDescription: true, + onDidTriggerItemButton: context => { + let task = context.item.task; + this.quickInputService.cancel(); + if (ContributedTask.is(task)) { + this.customize(task, undefined, true); + } else if (CustomTask.is(task)) { + this.openConfig(task); } - }); + } + }); } private showIgnoredFoldersMessage(): Promise { @@ -2152,7 +2173,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return taskPromise.then((taskMap) => { type EntryType = (IQuickPickItem & { task: Task; }) | (IQuickPickItem & { folder: IWorkspaceFolder; }); let entries: QuickPickInput[] = []; - if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { + if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY) { let tasks = taskMap.all(); let needsCreateOrOpen: boolean = true; if (tasks.length > 0) { diff --git a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts index 084a8ca25d..4f2f507216 100644 --- a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts @@ -260,6 +260,8 @@ let schema: IJSONSchema = { id: schemaId, description: 'Task definition file', type: 'object', + allowsTrailingCommas: true, + allowComments: true, default: { version: '2.0.0', tasks: [ diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index 846da0cf03..b73716c6d2 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -27,7 +27,8 @@ import Constants from 'vs/workbench/contrib/markers/browser/constants'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; -import { ITerminalService, ITerminalInstance, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService, ITerminalInstanceService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { IOutputService } from 'vs/workbench/contrib/output/common/output'; import { StartStopProblemCollector, WatchingProblemCollector, ProblemCollectorEventKind, ProblemHandlingStrategy } from 'vs/workbench/contrib/tasks/common/problemCollectors'; import { @@ -42,7 +43,6 @@ import { URI } from 'vs/base/common/uri'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { Schemas } from 'vs/base/common/network'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; -import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { env as processEnv, cwd as processCwd } from 'vs/base/common/process'; @@ -60,7 +60,7 @@ interface ActiveTerminalData { class VariableResolver { - constructor(public workspaceFolder: IWorkspaceFolder, public taskSystemInfo: TaskSystemInfo | undefined, private _values: Map, private _service: IConfigurationResolverService | undefined) { + constructor(public workspaceFolder: IWorkspaceFolder | undefined, public taskSystemInfo: TaskSystemInfo | undefined, private _values: Map, private _service: IConfigurationResolverService | undefined) { } resolve(value: string): string { return value.replace(/\$\{(.*?)\}/g, (match: string, variable: string) => { @@ -389,7 +389,7 @@ export class TerminalTaskSystem implements ITaskSystem { } } - private resolveVariablesFromSet(taskSystemInfo: TaskSystemInfo | undefined, workspaceFolder: IWorkspaceFolder, task: CustomTask | ContributedTask, variables: Set): Promise { + private resolveVariablesFromSet(taskSystemInfo: TaskSystemInfo | undefined, workspaceFolder: IWorkspaceFolder | undefined, task: CustomTask | ContributedTask, variables: Set): Promise { let isProcess = task.command && task.command.runtime === RuntimeType.Process; let options = task.command && task.command.options ? task.command.options : undefined; let cwd = options ? options.cwd : undefined; @@ -406,7 +406,7 @@ export class TerminalTaskSystem implements ITaskSystem { } let resolvedVariables: Promise; - if (taskSystemInfo) { + if (taskSystemInfo && workspaceFolder) { let resolveSet: ResolveSet = { variables }; @@ -463,10 +463,7 @@ export class TerminalTaskSystem implements ITaskSystem { private executeCommand(task: CustomTask | ContributedTask, trigger: string): Promise { const workspaceFolder = this.currentTask.workspaceFolder = task.getWorkspaceFolder(); - if (workspaceFolder === undefined) { - return Promise.reject(new Error(`Must have workspace folder${task._label}`)); - } - const systemInfo = this.currentTask.systemInfo = this.taskSystemInfoResolver(workspaceFolder); + const systemInfo: TaskSystemInfo | undefined = this.currentTask.systemInfo = workspaceFolder ? this.taskSystemInfoResolver(workspaceFolder) : undefined; let variables = new Set(); this.collectTaskVariables(variables, task); @@ -515,7 +512,7 @@ export class TerminalTaskSystem implements ITaskSystem { } } - private async executeInTerminal(task: CustomTask | ContributedTask, trigger: string, resolver: VariableResolver, workspaceFolder: IWorkspaceFolder): Promise { + private async executeInTerminal(task: CustomTask | ContributedTask, trigger: string, resolver: VariableResolver, workspaceFolder: IWorkspaceFolder | undefined): Promise { let terminal: ITerminalInstance | undefined = undefined; let executedCommand: string | undefined = undefined; let error: TaskError | undefined = undefined; @@ -569,7 +566,12 @@ export class TerminalTaskSystem implements ITaskSystem { }); this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Start, task, terminal.id)); const registeredLinkMatchers = this.registerLinkMatchers(terminal, problemMatchers); + let skipLine: boolean = (!!task.command.presentation && task.command.presentation.echo); const onData = terminal.onLineData((line) => { + if (skipLine) { + skipLine = false; + return; + } watchingProblemMatcher.processLine(line); if (!delayer) { delayer = new Async.Delayer(3000); @@ -647,7 +649,12 @@ export class TerminalTaskSystem implements ITaskSystem { let problemMatchers = this.resolveMatchers(resolver, task.configurationProperties.problemMatchers); let startStopProblemMatcher = new StartStopProblemCollector(problemMatchers, this.markerService, this.modelService, ProblemHandlingStrategy.Clean, this.fileService); const registeredLinkMatchers = this.registerLinkMatchers(terminal, problemMatchers); + let skipLine: boolean = (!!task.command.presentation && task.command.presentation.echo); const onData = terminal.onLineData((line) => { + if (skipLine) { + skipLine = false; + return; + } startStopProblemMatcher.processLine(line); }); promise = new Promise((resolve, reject) => { @@ -751,7 +758,7 @@ export class TerminalTaskSystem implements ITaskSystem { }); } - private createTerminalName(task: CustomTask | ContributedTask, workspaceFolder: IWorkspaceFolder): string { + private createTerminalName(task: CustomTask | ContributedTask): string { const needsFolderQualification = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; return nls.localize('TerminalTaskSystem.terminalName', 'Task - {0}', needsFolderQualification ? task.getQualifiedLabel() : task.configurationProperties.name); } @@ -764,14 +771,14 @@ export class TerminalTaskSystem implements ITaskSystem { return URI.from({ scheme: Schemas.file, path: this.environmentService.userHome }); } - private async createShellLaunchConfig(task: CustomTask | ContributedTask, workspaceFolder: IWorkspaceFolder, variableResolver: VariableResolver, platform: Platform.Platform, options: CommandOptions, command: CommandString, args: CommandString[], waitOnExit: boolean | string): Promise { + private async createShellLaunchConfig(task: CustomTask | ContributedTask, workspaceFolder: IWorkspaceFolder | undefined, variableResolver: VariableResolver, platform: Platform.Platform, options: CommandOptions, command: CommandString, args: CommandString[], waitOnExit: boolean | string): Promise { let shellLaunchConfig: IShellLaunchConfig; let isShellCommand = task.command.runtime === RuntimeType.Shell; let needsFolderQualification = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; - let terminalName = this.createTerminalName(task, workspaceFolder); + let terminalName = this.createTerminalName(task); let originalCommand = task.command.name; if (isShellCommand) { - const defaultConfig = await this.terminalInstanceService.getDefaultShellAndArgs(true, platform); + const defaultConfig = variableResolver.taskSystemInfo ? await variableResolver.taskSystemInfo.getDefaultShellAndArgs() : await this.terminalInstanceService.getDefaultShellAndArgs(true, platform); shellLaunchConfig = { name: terminalName, executable: defaultConfig.shell, args: defaultConfig.args, waitOnExit }; let shellSpecified: boolean = false; let shellOptions: ShellConfiguration | undefined = task.command.options && task.command.options.shell; @@ -836,7 +843,7 @@ export class TerminalTaskSystem implements ITaskSystem { shellArgs.push(commandLine); shellLaunchConfig.args = windowsShellArgs ? shellArgs.join(' ') : shellArgs; if (task.command.presentation && task.command.presentation.echo) { - if (needsFolderQualification) { + if (needsFolderQualification && workspaceFolder) { shellLaunchConfig.initialText = `\x1b[1m> Executing task in folder ${workspaceFolder.name}: ${commandLine} <\x1b[0m\n`; } else { shellLaunchConfig.initialText = `\x1b[1m> Executing task: ${commandLine} <\x1b[0m\n`; @@ -865,7 +872,7 @@ export class TerminalTaskSystem implements ITaskSystem { } return args.join(' '); }; - if (needsFolderQualification) { + if (needsFolderQualification && workspaceFolder) { shellLaunchConfig.initialText = `\x1b[1m> Executing task in folder ${workspaceFolder.name}: ${shellLaunchConfig.executable} ${getArgsToEcho(shellLaunchConfig.args)} <\x1b[0m\n`; } else { shellLaunchConfig.initialText = `\x1b[1m> Executing task: ${shellLaunchConfig.executable} ${getArgsToEcho(shellLaunchConfig.args)} <\x1b[0m\n`; @@ -876,7 +883,6 @@ export class TerminalTaskSystem implements ITaskSystem { if (options.cwd) { let cwd = options.cwd; if (!path.isAbsolute(cwd)) { - let workspaceFolder = task.getWorkspaceFolder(); if (workspaceFolder && (workspaceFolder.uri.scheme === 'file')) { cwd = path.join(workspaceFolder.uri.fsPath, cwd); } @@ -890,7 +896,7 @@ export class TerminalTaskSystem implements ITaskSystem { return shellLaunchConfig; } - private async createTerminal(task: CustomTask | ContributedTask, resolver: VariableResolver, workspaceFolder: IWorkspaceFolder): Promise<[ITerminalInstance | undefined, string | undefined, TaskError | undefined]> { + private async createTerminal(task: CustomTask | ContributedTask, resolver: VariableResolver, workspaceFolder: IWorkspaceFolder | undefined): Promise<[ITerminalInstance | undefined, string | undefined, TaskError | undefined]> { let platform = resolver.taskSystemInfo ? resolver.taskSystemInfo.platform : Platform.platform; let options = this.resolveOptions(resolver, task.command.options); @@ -919,7 +925,7 @@ export class TerminalTaskSystem implements ITaskSystem { this.currentTask.shellLaunchConfig = launchConfigs = { isExtensionTerminal: true, waitOnExit, - name: this.createTerminalName(task, workspaceFolder), + name: this.createTerminalName(task), initialText: task.command.presentation && task.command.presentation.echo ? `\x1b[1m> Executing task: ${task._label} <\x1b[0m\n` : undefined }; } else { diff --git a/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts b/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts index bbb9a408e8..6e70b59b24 100644 --- a/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts +++ b/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts @@ -481,6 +481,7 @@ tasks.items = { definitionsTaskRunnerConfigurationProperties.inputs = inputsSchema.definitions!.inputs; definitions.commandConfiguration.properties!.isShellCommand = Objects.deepClone(shellCommand); +definitions.commandConfiguration.properties!.args = Objects.deepClone(args); definitions.options.properties!.shell = { $ref: '#/definitions/shellConfiguration' }; diff --git a/src/vs/workbench/contrib/tasks/common/media/configure-hc.svg b/src/vs/workbench/contrib/tasks/common/media/configure-hc.svg new file mode 100644 index 0000000000..bd59cb81f6 --- /dev/null +++ b/src/vs/workbench/contrib/tasks/common/media/configure-hc.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/vs/workbench/contrib/tasks/common/media/task.contribution.css b/src/vs/workbench/contrib/tasks/common/media/task.contribution.css index 17b04b76f0..faa818475b 100644 --- a/src/vs/workbench/contrib/tasks/common/media/task.contribution.css +++ b/src/vs/workbench/contrib/tasks/common/media/task.contribution.css @@ -7,7 +7,10 @@ background-image: url('configure-light.svg'); } -.vs-dark .monaco-workbench .quick-open-task-configure, -.hc-black .monaco-workbench .quick-open-task-configure { +.vs-dark .monaco-workbench .quick-open-task-configure { background-image: url('configure-dark.svg'); } + +.hc-black .monaco-workbench .quick-open-task-configure { + background-image: url('configure-hc.svg'); +} diff --git a/src/vs/workbench/contrib/tasks/common/taskService.ts b/src/vs/workbench/contrib/tasks/common/taskService.ts index 2fedf4058d..e0caef8d16 100644 --- a/src/vs/workbench/contrib/tasks/common/taskService.ts +++ b/src/vs/workbench/contrib/tasks/common/taskService.ts @@ -51,7 +51,7 @@ export interface WorkspaceFolderTaskResult extends WorkspaceTaskResult { } export interface ITaskService { - _serviceBrand: any; + _serviceBrand: undefined; onDidStateChange: Event; supportsMultipleTaskExecutions: boolean; diff --git a/src/vs/workbench/contrib/tasks/common/taskSystem.ts b/src/vs/workbench/contrib/tasks/common/taskSystem.ts index 2f3b12bf39..8055f18071 100644 --- a/src/vs/workbench/contrib/tasks/common/taskSystem.ts +++ b/src/vs/workbench/contrib/tasks/common/taskSystem.ts @@ -119,6 +119,7 @@ export interface TaskSystemInfo { context: any; uriProvider: (this: void, path: string) => URI; resolveVariables(workspaceFolder: IWorkspaceFolder, toResolve: ResolveSet): Promise; + getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }>; } export interface TaskSystemInfoResolver { @@ -137,4 +138,4 @@ export interface ITaskSystem { terminateAll(): Promise; revealTask(task: Task): boolean; customExecutionComplete(task: Task, result: number): Promise; -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index d09bd63060..e84bdf0854 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -72,8 +72,6 @@ } .monaco-workbench .panel.integrated-terminal .split-view-view { - /* Make relative as terminal absolute positioning needs it deeper in the tree */ - position: relative; box-sizing: border-box; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index f46baeb075..9aecc9a026 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -23,9 +23,9 @@ import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/wor import { ClearSelectionTerminalAction, ClearTerminalAction, CopyTerminalSelectionAction, CreateNewInActiveWorkspaceTerminalAction, CreateNewTerminalAction, DeleteToLineStartTerminalAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, 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, ManageWorkspaceShellPermissionsTerminalCommand } 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, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS } 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, TERMINAL_ACTION_CATEGORY, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, TERMINAL_COMMAND_ID } 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 { setupTerminalCommands } from 'vs/workbench/contrib/terminal/browser/terminalCommands'; import { setupTerminalMenu } from 'vs/workbench/contrib/terminal/common/terminalMenu'; import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; import { EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; @@ -34,6 +34,7 @@ import { TerminalService } from 'vs/workbench/contrib/terminal/browser/terminalS 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'; +import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; registerSingleton(ITerminalService, TerminalService, true); @@ -194,10 +195,16 @@ configurationRegistry.registerConfiguration({ type: 'number', default: 1000 }, - 'terminal.integrated.setLocaleVariables': { - markdownDescription: nls.localize('terminal.integrated.setLocaleVariables', "Controls whether locale variables are set at startup of the terminal."), - type: 'boolean', - default: true + 'terminal.integrated.detectLocale': { + markdownDescription: nls.localize('terminal.integrated.detectLocale', "Controls whether to detect and set the `$LANG` environment variable to a UTF-8 compliant option since VS Code's terminal only supports UTF-8 encoded data coming from the shell."), + type: 'string', + enum: ['auto', 'off', 'on'], + enumDescriptions: [ + nls.localize('terminal.integrated.detectLocale.auto', "Set the `$LANG` environment variable if the existing variable does not exist or it does not end in `'.UTF-8'`."), + nls.localize('terminal.integrated.detectLocale.off', "Do not set the `$LANG` environment variable."), + nls.localize('terminal.integrated.detectLocale.on', "Always set the `$LANG` environment variable.") + ], + default: 'auto' }, 'terminal.integrated.rendererType': { type: 'string', diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 0b78c3477f..0ba28b304d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -6,11 +6,16 @@ import { Terminal as XTermTerminal } from 'xterm'; import { WebLinksAddon as XTermWebLinksAddon } from 'xterm-addon-web-links'; import { SearchAddon as XTermSearchAddon } from 'xterm-addon-search'; -import { ITerminalInstance, IWindowsShellHelper, ITerminalConfigHelper, ITerminalChildProcess, IShellLaunchConfig, IDefaultShellAndArgsRequest } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IWindowsShellHelper, ITerminalConfigHelper, ITerminalChildProcess, IShellLaunchConfig, IDefaultShellAndArgsRequest, ISpawnExtHostProcessRequest, IStartExtensionTerminalRequest, IAvailableShellsRequest, ITerminalProcessExtHostProxy, ICommandTracker, INavigationMode, TitleEventSource, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IProcessEnvironment, Platform } from 'vs/base/common/platform'; import { Event } from 'vs/base/common/event'; +import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { FindReplaceState } from 'vs/editor/contrib/find/findState'; +import { URI } from 'vs/base/common/uri'; +export const ITerminalService = createDecorator('terminalService'); export const ITerminalInstanceService = createDecorator('terminalInstanceService'); /** @@ -19,7 +24,7 @@ export const ITerminalInstanceService = createDecorator; @@ -37,3 +42,404 @@ export interface ITerminalInstanceService { export interface IBrowserTerminalConfigHelper extends ITerminalConfigHelper { panelContainer: HTMLElement | undefined; } + +export const enum Direction { + Left = 0, + Right = 1, + Up = 2, + Down = 3 +} + +export interface ITerminalTab { + activeInstance: ITerminalInstance | null; + terminalInstances: ITerminalInstance[]; + title: string; + onDisposed: Event; + onInstancesChanged: Event; + + focusPreviousPane(): void; + focusNextPane(): void; + resizePane(direction: Direction): void; + setActiveInstanceByIndex(index: number): void; + attachToElement(element: HTMLElement): void; + setVisible(visible: boolean): void; + layout(width: number, height: number): void; + addDisposable(disposable: IDisposable): void; + split(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance | undefined; +} + +export interface ITerminalService { + _serviceBrand: undefined; + + activeTabIndex: number; + configHelper: ITerminalConfigHelper; + terminalInstances: ITerminalInstance[]; + terminalTabs: ITerminalTab[]; + + onActiveTabChanged: Event; + onTabDisposed: Event; + onInstanceCreated: Event; + onInstanceDisposed: Event; + onInstanceProcessIdReady: Event; + onInstanceDimensionsChanged: Event; + onInstanceMaximumDimensionsChanged: Event; + onInstanceRequestSpawnExtHostProcess: Event; + onInstanceRequestStartExtensionTerminal: Event; + onInstancesChanged: Event; + onInstanceTitleChanged: Event; + onActiveInstanceChanged: Event; + onRequestAvailableShells: Event; + + /** + * Creates a terminal. + * @param shell The shell launch configuration to use. + */ + createTerminal(shell?: IShellLaunchConfig): ITerminalInstance; + + /** + * Creates a raw terminal instance, this should not be used outside of the terminal part. + */ + createInstance(container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance; + getInstanceFromId(terminalId: number): ITerminalInstance | undefined; + getInstanceFromIndex(terminalIndex: number): ITerminalInstance; + getTabLabels(): string[]; + getActiveInstance(): ITerminalInstance | null; + setActiveInstance(terminalInstance: ITerminalInstance): void; + setActiveInstanceByIndex(terminalIndex: number): void; + getActiveOrCreateInstance(): ITerminalInstance; + splitInstance(instance: ITerminalInstance, shell?: IShellLaunchConfig): ITerminalInstance | null; + + getActiveTab(): ITerminalTab | null; + setActiveTabToNext(): void; + setActiveTabToPrevious(): void; + setActiveTabByIndex(tabIndex: number): void; + + /** + * Fire the onActiveTabChanged event, this will trigger the terminal dropdown to be updated, + * among other things. + */ + refreshActiveTab(): void; + + showPanel(focus?: boolean): Promise; + hidePanel(): void; + focusFindWidget(): Promise; + hideFindWidget(): void; + getFindState(): FindReplaceState; + findNext(): void; + findPrevious(): void; + + selectDefaultWindowsShell(): Promise; + + setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; + manageWorkspaceShellPermissions(): void; + + /** + * Takes a path and returns the properly escaped path to send to the terminal. + * On Windows, this included trying to prepare the path for WSL if needed. + * + * @param executable The executable off the shellLaunchConfig + * @param title The terminal's title + * @param path The path to be escaped and formatted. + * @returns An escaped version of the path to be execuded in the terminal. + */ + preparePathForTerminalAsync(path: string, executable: string | undefined, title: string): Promise; + + extHostReady(remoteAuthority: string): void; + requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; + requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void; +} + +export interface ISearchOptions { + /** + * Whether the find should be done as a regex. + */ + regex?: boolean; + /** + * Whether only whole words should match. + */ + wholeWord?: boolean; + /** + * Whether find should pay attention to case. + */ + caseSensitive?: boolean; + /** + * Whether the search should start at the current search position (not the next row) + */ + incremental?: boolean; +} + +export interface ITerminalInstance { + /** + * The ID of the terminal instance, this is an arbitrary number only used to identify the + * terminal instance. + */ + readonly id: number; + + readonly cols: number; + readonly rows: number; + readonly maxCols: number; + readonly maxRows: number; + + /** + * The process ID of the shell process, this is undefined when there is no process associated + * with this terminal. + */ + processId: number | undefined; + + /** + * An event that fires when the terminal instance's title changes. + */ + onTitleChanged: Event; + + /** + * An event that fires when the terminal instance is disposed. + */ + onDisposed: Event; + + onFocused: Event; + onProcessIdReady: Event; + onRequestExtHostProcess: Event; + onDimensionsChanged: Event; + onMaximumDimensionsChanged: Event; + + onFocus: Event; + + /** + * Attach a listener to the raw data stream coming from the pty, including ANSI escape + * sequences. + */ + onData: Event; + + /** + * Attach a listener to listen for new lines added to this terminal instance. + * + * @param listener The listener function which takes new line strings added to the terminal, + * excluding ANSI escape sequences. The line event will fire when an LF character is added to + * the terminal (ie. the line is not wrapped). Note that this means that the line data will + * not fire for the last line, until either the line is ended with a LF character of the process + * is exited. The lineData string will contain the fully wrapped line, not containing any LF/CR + * characters. + */ + onLineData: Event; + + /** + * Attach a listener that fires when the terminal's pty process exits. The number in the event + * is the processes' exit code, an exit code of null means the process was killed as a result of + * the ITerminalInstance being disposed. + */ + onExit: Event; + + processReady: Promise; + + /** + * The title of the terminal. This is either title or the process currently running or an + * explicit name given to the terminal instance through the extension API. + */ + readonly title: string; + + /** + * The focus state of the terminal before exiting. + */ + readonly hadFocusOnExit: boolean; + + /** + * False when the title is set by an API or the user. We check this to make sure we + * do not override the title when the process title changes in the terminal. + */ + isTitleSetByProcess: boolean; + + /** + * The shell launch config used to launch the shell. + */ + readonly shellLaunchConfig: IShellLaunchConfig; + + /** + * Whether to disable layout for the terminal. This is useful when the size of the terminal is + * being manipulating (e.g. adding a split pane) and we want the terminal to ignore particular + * resize events. + */ + disableLayout: boolean; + + /** + * An object that tracks when commands are run and enables navigating and selecting between + * them. + */ + readonly commandTracker: ICommandTracker | undefined; + + readonly navigationMode: INavigationMode | undefined; + + /** + * Dispose the terminal instance, removing it from the panel/service and freeing up resources. + * + * @param immediate Whether the kill should be immediate or not. Immediate should only be used + * when VS Code is shutting down or in cases where the terminal dispose was user initiated. + * The immediate===false exists to cover an edge case where the final output of the terminal can + * get cut off. If immediate kill any terminal processes immediately. + */ + dispose(immediate?: boolean): void; + + /** + * Forces the terminal to redraw its viewport. + */ + forceRedraw(): void; + + /** + * Registers a link matcher, allowing custom link patterns to be matched and handled. + * @param regex The regular expression the search for, specifically this searches the + * textContent of the rows. You will want to use \s to match a space ' ' character for example. + * @param handler The callback when the link is called. + * @param matchIndex The index of the link from the regex.match(html) call. This defaults to 0 + * (for regular expressions without capture groups). + * @param validationCallback A callback which can be used to validate the link after it has been + * added to the DOM. + * @return The ID of the new matcher, this can be used to deregister. + */ + registerLinkMatcher(regex: RegExp, handler: (url: string) => void, matchIndex?: number, validationCallback?: (uri: string, callback: (isValid: boolean) => void) => void): number; + + /** + * Deregisters a link matcher if it has been registered. + * @param matcherId The link matcher's ID (returned after register) + * @return Whether a link matcher was found and deregistered. + */ + deregisterLinkMatcher(matcherId: number): void; + + /** + * Check if anything is selected in terminal. + */ + hasSelection(): boolean; + + /** + * Copies the terminal selection to the clipboard. + */ + copySelection(): Promise; + + /** + * Current selection in the terminal. + */ + readonly selection: string | undefined; + + /** + * Clear current selection. + */ + clearSelection(): void; + + /** + * Select all text in the terminal. + */ + selectAll(): void; + + /** + * Find the next instance of the term + */ + findNext(term: string, searchOptions: ISearchOptions): boolean; + + /** + * Find the previous instance of the term + */ + findPrevious(term: string, searchOptions: ISearchOptions): boolean; + + /** + * Notifies the terminal that the find widget's focus state has been changed. + */ + notifyFindWidgetFocusChanged(isFocused: boolean): void; + + /** + * Focuses the terminal instance if it's able to (xterm.js instance exists). + * + * @param focus Force focus even if there is a selection. + */ + focus(force?: boolean): void; + + /** + * Focuses the terminal instance when it's ready (the xterm.js instance is created). Use this + * when the terminal is being shown. + * + * @param focus Force focus even if there is a selection. + */ + focusWhenReady(force?: boolean): Promise; + + /** + * Focuses and pastes the contents of the clipboard into the terminal instance. + */ + paste(): Promise; + + /** + * Send text to the terminal instance. The text is written to the stdin of the underlying pty + * process (shell) of the terminal instance. + * + * @param text The text to send. + * @param addNewLine Whether to add a new line to the text being sent, this is normally + * required to run a command in the terminal. The character(s) added are \n or \r\n + * depending on the platform. This defaults to `true`. + */ + sendText(text: string, addNewLine: boolean): void; + + /** + * Write text directly to the terminal, skipping the process if it exists. + * @param text The text to write. + */ + write(text: string): void; + + /** Scroll the terminal buffer down 1 line. */ + scrollDownLine(): void; + /** Scroll the terminal buffer down 1 page. */ + scrollDownPage(): void; + /** Scroll the terminal buffer to the bottom. */ + scrollToBottom(): void; + /** Scroll the terminal buffer up 1 line. */ + scrollUpLine(): void; + /** Scroll the terminal buffer up 1 page. */ + scrollUpPage(): void; + /** Scroll the terminal buffer to the top. */ + scrollToTop(): void; + + /** + * Clears the terminal buffer, leaving only the prompt line. + */ + clear(): void; + + /** + * Attaches the terminal instance to an element on the DOM, before this is called the terminal + * instance process may run in the background but cannot be displayed on the UI. + * + * @param container The element to attach the terminal instance to. + */ + attachToElement(container: HTMLElement): void; + + /** + * Configure the dimensions of the terminal instance. + * + * @param dimension The dimensions of the container. + */ + layout(dimension: { width: number, height: number }): void; + + /** + * Sets whether the terminal instance's element is visible in the DOM. + * + * @param visible Whether the element is visible. + */ + setVisible(visible: boolean): void; + + /** + * Immediately kills the terminal's current pty process and launches a new one to replace it. + * + * @param shell The new launch configuration. + */ + reuseTerminal(shell: IShellLaunchConfig): void; + + /** + * Sets the title of the terminal instance. + */ + setTitle(title: string, eventSource: TitleEventSource): void; + + waitForTitle(): Promise; + + setDimensions(dimensions: ITerminalDimensions): void; + + addDisposable(disposable: IDisposable): void; + + toggleEscapeSequenceLogging(): void; + + getInitialCwd(): Promise; + getCwd(): Promise; +} diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 0b725ab686..af21f393f3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { Action, IAction } from 'vs/base/common/actions'; import { EndOfLinePreference } from 'vs/editor/common/model'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, Direction, ITerminalConfigHelper, TitleEventSource } from 'vs/workbench/contrib/terminal/common/terminal'; +import { TERMINAL_PANEL_ID, ITerminalConfigHelper, TitleEventSource, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal'; import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { TogglePanelAction } from 'vs/workbench/browser/panel'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; @@ -24,7 +24,6 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; import { Command } from 'vs/editor/browser/editorExtensions'; import { timeout } from 'vs/base/common/async'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; @@ -35,6 +34,7 @@ import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { isWindows } from 'vs/base/common/platform'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { ITerminalInstance, ITerminalService, Direction } from 'vs/workbench/contrib/terminal/browser/terminal'; export const TERMINAL_PICKER_PREFIX = 'term '; @@ -231,8 +231,8 @@ export class DeleteWordRightTerminalAction extends BaseSendTextTerminalAction { label: string, @ITerminalService terminalService: ITerminalService ) { - // Send alt+D - super(id, label, '\x1bD', terminalService); + // Send alt+d + super(id, label, '\x1bd', terminalService); } } @@ -549,7 +549,7 @@ export class FocusActiveTerminalAction extends Action { } public run(event?: any): Promise { - const instance = this.terminalService.getActiveOrCreateInstance(true); + const instance = this.terminalService.getActiveOrCreateInstance(); if (!instance) { return Promise.resolve(undefined); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalCommands.ts b/src/vs/workbench/contrib/terminal/browser/terminalCommands.ts new file mode 100644 index 0000000000..9960d1faf5 --- /dev/null +++ b/src/vs/workbench/contrib/terminal/browser/terminalCommands.ts @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; + +export function setupTerminalCommands(): void { + registerOpenTerminalAtIndexCommands(); +} + +function registerOpenTerminalAtIndexCommands(): void { + for (let i = 0; i < 9; i++) { + const terminalIndex = i; + const visibleIndex = i + 1; + + KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: `workbench.action.terminal.focusAtIndex${visibleIndex}`, + weight: KeybindingWeight.WorkbenchContrib, + when: undefined, + primary: 0, + handler: accessor => { + const terminalService = accessor.get(ITerminalService); + terminalService.setActiveInstanceByIndex(terminalIndex); + return terminalService.showPanel(true); + } + }); + } +} diff --git a/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts index f737123c7c..970a4e4499 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts @@ -10,7 +10,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ITerminalConfiguration, ITerminalFont, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, TERMINAL_CONFIG_SECTION, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, MINIMUM_LETTER_SPACING, LinuxDistro, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; import Severity from 'vs/base/common/severity'; -import { Terminal as XTermTerminal } from 'xterm'; import { INotificationService, NeverShowAgainScope } from 'vs/platform/notification/common/notification'; import { IBrowserTerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminal'; import { Emitter, Event } from 'vs/base/common/event'; @@ -21,6 +20,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { InstallRecommendedExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { IProductService } from 'vs/platform/product/common/product'; +import { XTermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; const MINIMUM_FONT_SIZE = 6; const MAXIMUM_FONT_SIZE = 25; @@ -129,7 +129,7 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper { * Gets the font information based on the terminal.integrated.fontFamily * terminal.integrated.fontSize, terminal.integrated.lineHeight configuration properties */ - public getFont(xterm?: XTermTerminal, excludeDimensions?: boolean): ITerminalFont { + public getFont(xtermCore?: XTermCore, excludeDimensions?: boolean): ITerminalFont { const editorConfig = this._configurationService.getValue('editor'); let fontFamily = this.config.fontFamily || editorConfig.fontFamily || EDITOR_FONT_DEFAULTS.fontFamily; @@ -161,15 +161,15 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper { } // Get the character dimensions from xterm if it's available - if (xterm) { - if (xterm._core._charSizeService && xterm._core._charSizeService.width && xterm._core._charSizeService.height) { + if (xtermCore) { + if (xtermCore._charSizeService && xtermCore._charSizeService.width && xtermCore._charSizeService.height) { return { fontFamily, fontSize, letterSpacing, lineHeight, - charHeight: xterm._core._charSizeService.height, - charWidth: xterm._core._charSizeService.width + charHeight: xtermCore._charSizeService.height, + charWidth: xtermCore._charSizeService.width }; } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts index f5944e3c0a..cc8df81642 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts @@ -5,9 +5,10 @@ import { SimpleFindWidget } from 'vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; -import { ITerminalService, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED } from 'vs/workbench/contrib/terminal/common/terminal'; +import { KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED } from 'vs/workbench/contrib/terminal/common/terminal'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; +import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; export class TerminalFindWidget extends SimpleFindWidget { protected _findInputFocused: IContextKey; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 4ee386ffc6..5f56cb9264 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -25,19 +25,19 @@ 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, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, INavigationMode, TitleEventSource } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IShellLaunchConfig, ITerminalDimensions, 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, TitleEventSource, TERMINAL_COMMAND_ID } 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'; import { TerminalLinkHandler } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler'; 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 { ITerminalInstanceService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager'; import { Terminal as XTermTerminal, IBuffer, ITerminalAddon } from 'xterm'; import { SearchAddon, ISearchOptions } from 'xterm-addon-search'; import { CommandTrackerAddon } from 'vs/workbench/contrib/terminal/browser/addons/commandTrackerAddon'; import { NavigationModeAddon } from 'vs/workbench/contrib/terminal/browser/addons/navigationModeAddon'; +import { XTermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; // How long in milliseconds should an average frame take to render for a notification to appear // which suggests the fallback DOM-based renderer @@ -184,6 +184,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _title: string = ''; private _wrapperElement: (HTMLElement & { xterm?: XTermTerminal }) | undefined; private _xterm: XTermTerminal | undefined; + private _xtermCore: XTermCore | undefined; private _xtermSearch: SearchAddon | undefined; private _xtermElement: HTMLDivElement | undefined; private _terminalHasTextContextKey: IContextKey; @@ -351,7 +352,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return null; } - const font = this._configHelper.getFont(this._xterm); + const font = this._configHelper.getFont(this._xtermCore); if (!font.charWidth || !font.charHeight) { this._setLastKnownColsAndRows(); return null; @@ -399,7 +400,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _getDimension(width: number, height: number): ICanvasDimensions | undefined { // The font needs to have been initialized - const font = this._configHelper.getFont(this._xterm); + const font = this._configHelper.getFont(this._xtermCore); if (!font || !font.charWidth || !font.charHeight) { return undefined; } @@ -412,8 +413,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // needs to happen otherwise its scrollTop value is invalid when the panel is toggled as // it gets removed and then added back to the DOM (resetting scrollTop to 0). // Upstream issue: https://github.com/sourcelair/xterm.js/issues/291 - if (this._xterm) { - this._xterm._core._onScroll.fire(this._xterm.buffer.viewportY); + if (this._xterm && this._xtermCore) { + this._xtermCore._onScroll.fire(this._xterm.buffer.viewportY); } } @@ -472,6 +473,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType }); this._xterm = xterm; + this._xtermCore = (xterm as any)._core as XTermCore; this.updateAccessibilitySupport(); this._terminalInstanceService.getXtermSearchConstructor().then(Addon => { this._xtermSearch = new Addon(); @@ -674,9 +676,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } private async _measureRenderTime(): Promise { - const xterm = await this._xtermReadyPromise; + await this._xtermReadyPromise; const frameTimes: number[] = []; - const textRenderLayer = xterm._core._renderService._renderer._renderLayers[0]; + const textRenderLayer = this._xtermCore!._renderService._renderer._renderLayers[0]; const originalOnGridChanged = textRenderLayer.onGridChanged; const evaluateCanvasRenderer = () => { @@ -893,12 +895,12 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { if (this._wrapperElement) { dom.toggleClass(this._wrapperElement, 'active', visible); } - if (visible && this._xterm) { + if (visible && this._xterm && this._xtermCore) { // Trigger a manual scroll event which will sync the viewport and scroll bar. This is // necessary if the number of rows in the terminal has decreased while it was in the // background since scrollTop changes take no effect but the terminal's position does // change since the number of visible rows decreases. - this._xterm._core._onScroll.fire(this._xterm.buffer.viewportY); + this._xtermCore._onScroll.fire(this._xterm.buffer.viewportY); if (this._container && this._container.parentElement) { // Force a layout when the instance becomes invisible. This is particularly important // for ensuring that terminals that are created in the background by an extension will @@ -1322,11 +1324,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { let cols = this.cols; let rows = this.rows; - if (this._xterm) { + if (this._xterm && this._xtermCore) { // Only apply these settings when the terminal is visible so that // the characters are measured correctly. if (this._isVisible) { - const font = this._configHelper.getFont(this._xterm); + const font = this._configHelper.getFont(this._xtermCore); const config = this._configHelper.config; this._safeSetOption('letterSpacing', font.letterSpacing); this._safeSetOption('lineHeight', font.lineHeight); @@ -1354,7 +1356,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // maximize on Windows/Linux would fire an event saying that the terminal was not // visible. if (this._xterm.getOption('rendererType') === 'canvas') { - this._xterm._core._renderService._onIntersectionChange({ intersectionRatio: 1 }); + this._xtermCore._renderService._onIntersectionChange({ intersectionRatio: 1 }); // HACK: Force a refresh of the screen to ensure links are refresh corrected. // This can probably be removed when the above hack is fixed in Chromium. this._xterm.refresh(0, this._xterm.rows - 1); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts index 709f99782d..9e15c88582 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts @@ -17,7 +17,7 @@ let WebLinksAddon: typeof XTermWebLinksAddon; let SearchAddon: typeof XTermSearchAddon; export class TerminalInstanceService implements ITerminalInstanceService { - public _serviceBrand: any; + public _serviceBrand: undefined; private readonly _onRequestDefaultShellAndArgs = new Emitter(); public get onRequestDefaultShellAndArgs(): Event { return this._onRequestDefaultShellAndArgs.event; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalNativeService.ts b/src/vs/workbench/contrib/terminal/browser/terminalNativeService.ts index bdaed4197a..c93133c43c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalNativeService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalNativeService.ts @@ -9,7 +9,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class TerminalNativeService implements ITerminalNativeService { - public _serviceBrand: any; + public _serviceBrand: undefined; public get linuxDistro(): LinuxDistro { return LinuxDistro.Unknown; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts index 215bf89bed..f2040ec224 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts @@ -12,7 +12,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { ITerminalService, TERMINAL_PANEL_ID } from 'vs/workbench/contrib/terminal/common/terminal'; +import { TERMINAL_PANEL_ID } from 'vs/workbench/contrib/terminal/common/terminal'; import { IThemeService, ITheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; import { editorHoverBackground, editorHoverBorder, editorForeground } from 'vs/platform/theme/common/colorRegistry'; @@ -24,6 +24,7 @@ import { TERMINAL_BACKGROUND_COLOR, TERMINAL_BORDER_COLOR } from 'vs/workbench/c import { DataTransfers } from 'vs/base/browser/dnd'; import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification'; import { IStorageService } from 'vs/platform/storage/common/storage'; +import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; const FIND_FOCUS_CLASS = 'find-focused'; diff --git a/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts similarity index 95% rename from src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts rename to src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts index 5661101a87..55b546b3ea 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts @@ -4,11 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import { Event, Emitter } from 'vs/base/common/event'; -import { ITerminalService, ITerminalProcessExtHostProxy, IShellLaunchConfig, ITerminalChildProcess, ITerminalConfigHelper, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalProcessExtHostProxy, IShellLaunchConfig, ITerminalChildProcess, ITerminalConfigHelper, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal'; import { Disposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import * as nls from 'vs/nls'; +import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; let hasReceivedResponse: boolean = false; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 2fad6bd4f3..fd767e7f93 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -10,7 +10,7 @@ import { ProcessState, ITerminalProcessManager, IShellLaunchConfig, ITerminalCon import { ILogService } from 'vs/platform/log/common/log'; import { Emitter, Event } from 'vs/base/common/event'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { TerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy'; +import { TerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; @@ -227,7 +227,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce const isWorkspaceShellAllowed = this._configHelper.checkWorkspaceShellPermissions(); this._configHelper.showRecommendations(shellLaunchConfig); const baseEnv = this._configHelper.config.inheritEnv ? processEnv : await this._terminalInstanceService.getMainProcessParentEnv(); - const env = terminalEnvironment.createTerminalEnvironment(shellLaunchConfig, lastActiveWorkspace, envFromConfigValue, this._configurationResolverService, isWorkspaceShellAllowed, this._productService.version, this._configHelper.config.setLocaleVariables, baseEnv); + const env = terminalEnvironment.createTerminalEnvironment(shellLaunchConfig, lastActiveWorkspace, envFromConfigValue, this._configurationResolverService, isWorkspaceShellAllowed, this._productService.version, this._configHelper.config.detectLocale, baseEnv); const useConpty = this._configHelper.config.windowsEnableConpty && !isScreenReaderModeEnabled; return this._terminalInstanceService.createTerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, useConpty); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickOpen.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickOpen.ts index 20eba8bfde..1fc468034b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickOpen.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickOpen.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { Mode, IEntryRunContext, IAutoFocus, IQuickNavigateConfiguration, IModel } from 'vs/base/parts/quickopen/common/quickOpen'; import { QuickOpenModel, QuickOpenEntry } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { QuickOpenHandler } from 'vs/workbench/browser/quickopen'; -import { ITerminalService, ITerminalInstance } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { ContributableActionProvider } from 'vs/workbench/browser/actions'; import { stripWildcards } from 'vs/base/common/strings'; import { matchesFuzzy } from 'vs/base/common/filters'; @@ -134,4 +134,4 @@ export class TerminalPickerHandler extends QuickOpenHandler { } return nls.localize('noTerminalsFound', "No terminals open"); } -} \ 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 6fa5c1d18e..7d05daa9e1 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -3,13 +3,12 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper, ITerminalNativeService } from 'vs/workbench/contrib/terminal/common/terminal'; -import { TerminalService as CommonTerminalService } from 'vs/workbench/contrib/terminal/common/terminalService'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import * as nls from 'vs/nls'; +import { TERMINAL_PANEL_ID, IShellLaunchConfig, ITerminalConfigHelper, ITerminalNativeService, ISpawnExtHostProcessRequest, IStartExtensionTerminalRequest, IAvailableShellsRequest, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalProcessExtHostProxy, IShellDefinition } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { IStorageService } from 'vs/platform/storage/common/storage'; import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -18,38 +17,578 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance'; -import { IBrowserTerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { IBrowserTerminalConfigHelper, ITerminalService, ITerminalInstance, ITerminalTab } from 'vs/workbench/contrib/terminal/browser/terminal'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; -import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { Event, Emitter } from 'vs/base/common/event'; +import { URI } from 'vs/base/common/uri'; +import { FindReplaceState } from 'vs/editor/contrib/find/findState'; +import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; +import { isWindows, isMacintosh, OperatingSystem } from 'vs/base/common/platform'; +import { basename } from 'vs/base/common/path'; +import { IOpenFileRequest } from 'vs/platform/windows/common/windows'; + +interface IExtHostReadyEntry { + promise: Promise; + resolve: () => void; +} + +export class TerminalService implements ITerminalService { + public _serviceBrand: undefined; + + protected _isShuttingDown: boolean; + protected _terminalFocusContextKey: IContextKey; + protected _findWidgetVisible: IContextKey; + protected _terminalTabs: ITerminalTab[] = []; + protected _backgroundedTerminalInstances: ITerminalInstance[] = []; + protected get _terminalInstances(): ITerminalInstance[] { + return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), []); + } + private _findState: FindReplaceState; + private _extHostsReady: { [authority: string]: IExtHostReadyEntry | undefined } = {}; + private _activeTabIndex: number; + + public get activeTabIndex(): number { return this._activeTabIndex; } + public get terminalInstances(): ITerminalInstance[] { return this._terminalInstances; } + public get terminalTabs(): ITerminalTab[] { return this._terminalTabs; } -export class TerminalService extends CommonTerminalService implements ITerminalService { private _configHelper: IBrowserTerminalConfigHelper; private _terminalContainer: HTMLElement | undefined; public get configHelper(): ITerminalConfigHelper { return this._configHelper; } + protected readonly _onActiveTabChanged = new Emitter(); + public get onActiveTabChanged(): Event { return this._onActiveTabChanged.event; } + protected readonly _onInstanceCreated = new Emitter(); + public get onInstanceCreated(): Event { return this._onInstanceCreated.event; } + protected readonly _onInstanceDisposed = new Emitter(); + public get onInstanceDisposed(): Event { return this._onInstanceDisposed.event; } + protected readonly _onInstanceProcessIdReady = new Emitter(); + public get onInstanceProcessIdReady(): Event { return this._onInstanceProcessIdReady.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(); + public get onInstanceMaximumDimensionsChanged(): Event { return this._onInstanceMaximumDimensionsChanged.event; } + protected readonly _onInstancesChanged = new Emitter(); + public get onInstancesChanged(): Event { return this._onInstancesChanged.event; } + protected readonly _onInstanceTitleChanged = new Emitter(); + public get onInstanceTitleChanged(): Event { return this._onInstanceTitleChanged.event; } + protected readonly _onActiveInstanceChanged = new Emitter(); + public get onActiveInstanceChanged(): Event { return this._onActiveInstanceChanged.event; } + protected readonly _onTabDisposed = new Emitter(); + public get onTabDisposed(): Event { return this._onTabDisposed.event; } + protected readonly _onRequestAvailableShells = new Emitter(); + public get onRequestAvailableShells(): Event { return this._onRequestAvailableShells.event; } + constructor( - @IContextKeyService contextKeyService: IContextKeyService, - @IPanelService panelService: IPanelService, + @IContextKeyService private _contextKeyService: IContextKeyService, + @IPanelService private _panelService: IPanelService, @IWorkbenchLayoutService private _layoutService: IWorkbenchLayoutService, @ILifecycleService lifecycleService: ILifecycleService, - @IStorageService storageService: IStorageService, - @INotificationService notificationService: INotificationService, - @IDialogService dialogService: IDialogService, - @IInstantiationService protected readonly _instantiationService: IInstantiationService, - @IExtensionService extensionService: IExtensionService, - @IFileService fileService: IFileService, - @IRemoteAgentService remoteAgentService: IRemoteAgentService, - @ITerminalNativeService readonly terminalNativeService: ITerminalNativeService, - @IQuickInputService readonly quickInputService: IQuickInputService, - @IConfigurationService readonly configurationService: IConfigurationService + @INotificationService private _notificationService: INotificationService, + @IDialogService private _dialogService: IDialogService, + @IInstantiationService private _instantiationService: IInstantiationService, + @IExtensionService private _extensionService: IExtensionService, + @IFileService private _fileService: IFileService, + @IRemoteAgentService private _remoteAgentService: IRemoteAgentService, + @ITerminalNativeService private _terminalNativeService: ITerminalNativeService, + @IQuickInputService private _quickInputService: IQuickInputService, + @IConfigurationService private _configurationService: IConfigurationService ) { - super(contextKeyService, panelService, lifecycleService, storageService, notificationService, dialogService, extensionService, fileService, remoteAgentService, terminalNativeService, quickInputService, configurationService); - this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, this.terminalNativeService.linuxDistro); + this._activeTabIndex = 0; + this._isShuttingDown = false; + this._findState = new FindReplaceState(); + lifecycleService.onBeforeShutdown(event => event.veto(this._onBeforeShutdown())); + lifecycleService.onShutdown(() => this._onShutdown()); + this._terminalNativeService.onOpenFileRequest(e => this._onOpenFileRequest(e)); + this._terminalNativeService.onOsResume(() => this._onOsResume()); + this._terminalFocusContextKey = KEYBINDING_CONTEXT_TERMINAL_FOCUS.bindTo(this._contextKeyService); + this._findWidgetVisible = KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE.bindTo(this._contextKeyService); + this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, this._terminalNativeService.linuxDistro); + this.onTabDisposed(tab => this._removeTab(tab)); + this.onActiveTabChanged(() => { + const instance = this.getActiveInstance(); + this._onActiveInstanceChanged.fire(instance ? instance : undefined); + }); + + this._handleContextKeys(); } + private _handleContextKeys(): void { + const terminalIsOpenContext = KEYBINDING_CONTEXT_TERMINAL_IS_OPEN.bindTo(this._contextKeyService); + + const updateTerminalContextKeys = () => { + terminalIsOpenContext.set(this.terminalInstances.length > 0); + }; + + this.onInstancesChanged(() => updateTerminalContextKeys()); + } + + public getActiveOrCreateInstance(): ITerminalInstance { + const activeInstance = this.getActiveInstance(); + return activeInstance ? activeInstance : this.createTerminal(undefined); + } + + 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 firing + // the event to spawn the ext host process + const conn = this._remoteAgentService.getConnection(); + const remoteAuthority = conn ? conn.remoteAuthority : 'null'; + await this._whenExtHostReady(remoteAuthority); + this._onInstanceRequestSpawnExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, isWorkspaceShellAllowed }); + }); + } + + public requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void { + this._onInstanceRequestStartExtensionTerminal.fire({ proxy, cols, rows }); + } + + 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 { + if (this.terminalInstances.length === 0) { + // No terminal instances, don't veto + return false; + } + + if (this.configHelper.config.confirmOnExit) { + // veto if configured to show confirmation and the user choosed not to exit + return this._showTerminalCloseConfirmation().then(veto => { + if (!veto) { + this._isShuttingDown = true; + } + return veto; + }); + } + + this._isShuttingDown = true; + + return false; + } + + private _onShutdown(): void { + // Dispose of all instances + this.terminalInstances.forEach(instance => instance.dispose(true)); + } + + private _onOpenFileRequest(request: IOpenFileRequest): void { + // if the request to open files is coming in from the integrated terminal (identified though + // the termProgram variable) and we are instructed to wait for editors close, wait for the + // marker file to get deleted and then focus back to the integrated terminal. + if (request.termProgram === 'vscode' && request.filesToWait) { + const waitMarkerFileUri = URI.revive(request.filesToWait.waitMarkerFileUri); + this._terminalNativeService.whenFileDeleted(waitMarkerFileUri).then(() => { + if (this.terminalInstances.length > 0) { + const terminal = this.getActiveInstance(); + if (terminal) { + terminal.focus(); + } + } + }); + } + } + + private _onOsResume(): void { + const activeTab = this.getActiveTab(); + if (!activeTab) { + return; + } + activeTab.terminalInstances.forEach(instance => instance.forceRedraw()); + } + + public getTabLabels(): string[] { + return this._terminalTabs.filter(tab => tab.terminalInstances.length > 0).map((tab, index) => `${index + 1}: ${tab.title ? tab.title : ''}`); + } + + public getFindState(): FindReplaceState { + return this._findState; + } + + private _removeTab(tab: ITerminalTab): void { + // Get the index of the tab and remove it from the list + const index = this._terminalTabs.indexOf(tab); + const wasActiveTab = tab === this.getActiveTab(); + if (index !== -1) { + this._terminalTabs.splice(index, 1); + } + + // Adjust focus if the tab was active + if (wasActiveTab && this._terminalTabs.length > 0) { + // TODO: Only focus the new tab if the removed tab had focus? + // const hasFocusOnExit = tab.activeInstance.hadFocusOnExit; + const newIndex = index < this._terminalTabs.length ? index : this._terminalTabs.length - 1; + this.setActiveTabByIndex(newIndex); + const activeInstance = this.getActiveInstance(); + if (activeInstance) { + activeInstance.focus(true); + } + } + + // Hide the panel if there are no more instances, provided that VS Code is not shutting + // down. When shutting down the panel is locked in place so that it is restored upon next + // launch. + if (this._terminalTabs.length === 0 && !this._isShuttingDown) { + this.hidePanel(); + this._onActiveInstanceChanged.fire(undefined); + } + + // Fire events + this._onInstancesChanged.fire(); + if (wasActiveTab) { + this._onActiveTabChanged.fire(); + } + } + + public refreshActiveTab(): void { + // Fire active instances changed + this._onActiveTabChanged.fire(); + } + + public getActiveTab(): ITerminalTab | null { + if (this._activeTabIndex < 0 || this._activeTabIndex >= this._terminalTabs.length) { + return null; + } + return this._terminalTabs[this._activeTabIndex]; + } + + public getActiveInstance(): ITerminalInstance | null { + const tab = this.getActiveTab(); + if (!tab) { + return null; + } + return tab.activeInstance; + } + + public getInstanceFromId(terminalId: number): ITerminalInstance | undefined { + let bgIndex = -1; + this._backgroundedTerminalInstances.forEach((terminalInstance, i) => { + if (terminalInstance.id === terminalId) { + bgIndex = i; + } + }); + if (bgIndex !== -1) { + return this._backgroundedTerminalInstances[bgIndex]; + } + try { + return this.terminalInstances[this._getIndexFromId(terminalId)]; + } catch { + return undefined; + } + } + + public getInstanceFromIndex(terminalIndex: number): ITerminalInstance { + return this.terminalInstances[terminalIndex]; + } + + public setActiveInstance(terminalInstance: ITerminalInstance): void { + // If this was a hideFromUser terminal created by the API this was triggered by show, + // in which case we need to create the terminal tab + if (terminalInstance.shellLaunchConfig.hideFromUser) { + this._showBackgroundTerminal(terminalInstance); + } + this.setActiveInstanceByIndex(this._getIndexFromId(terminalInstance.id)); + } + + public setActiveTabByIndex(tabIndex: number): void { + if (tabIndex >= this._terminalTabs.length) { + return; + } + + const didTabChange = this._activeTabIndex !== tabIndex; + this._activeTabIndex = tabIndex; + + this._terminalTabs.forEach((t, i) => t.setVisible(i === this._activeTabIndex)); + if (didTabChange) { + this._onActiveTabChanged.fire(); + } + } + + private _getInstanceFromGlobalInstanceIndex(index: number): { tab: ITerminalTab, tabIndex: number, instance: ITerminalInstance, localInstanceIndex: number } | null { + let currentTabIndex = 0; + while (index >= 0 && currentTabIndex < this._terminalTabs.length) { + const tab = this._terminalTabs[currentTabIndex]; + const count = tab.terminalInstances.length; + if (index < count) { + return { + tab, + tabIndex: currentTabIndex, + instance: tab.terminalInstances[index], + localInstanceIndex: index + }; + } + index -= count; + currentTabIndex++; + } + return null; + } + + public setActiveInstanceByIndex(terminalIndex: number): void { + const query = this._getInstanceFromGlobalInstanceIndex(terminalIndex); + if (!query) { + return; + } + + query.tab.setActiveInstanceByIndex(query.localInstanceIndex); + const didTabChange = this._activeTabIndex !== query.tabIndex; + this._activeTabIndex = query.tabIndex; + this._terminalTabs.forEach((t, i) => t.setVisible(i === query.tabIndex)); + + // Only fire the event if there was a change + if (didTabChange) { + this._onActiveTabChanged.fire(); + } + } + + public setActiveTabToNext(): void { + if (this._terminalTabs.length <= 1) { + return; + } + let newIndex = this._activeTabIndex + 1; + if (newIndex >= this._terminalTabs.length) { + newIndex = 0; + } + this.setActiveTabByIndex(newIndex); + } + + public setActiveTabToPrevious(): void { + if (this._terminalTabs.length <= 1) { + return; + } + let newIndex = this._activeTabIndex - 1; + if (newIndex < 0) { + newIndex = this._terminalTabs.length - 1; + } + this.setActiveTabByIndex(newIndex); + } + + public splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfig: IShellLaunchConfig = {}): ITerminalInstance | null { + const tab = this._getTabForInstance(instanceToSplit); + if (!tab) { + return null; + } + + const instance = tab.split(this._terminalFocusContextKey, this.configHelper, shellLaunchConfig); + if (!instance) { + this._showNotEnoughSpaceToast(); + return null; + } + + this._initInstanceListeners(instance); + this._onInstancesChanged.fire(); + + this._terminalTabs.forEach((t, i) => t.setVisible(i === this._activeTabIndex)); + return instance; + } + + protected _initInstanceListeners(instance: ITerminalInstance): void { + instance.addDisposable(instance.onDisposed(this._onInstanceDisposed.fire, this._onInstanceDisposed)); + instance.addDisposable(instance.onTitleChanged(this._onInstanceTitleChanged.fire, this._onInstanceTitleChanged)); + instance.addDisposable(instance.onProcessIdReady(this._onInstanceProcessIdReady.fire, this._onInstanceProcessIdReady)); + instance.addDisposable(instance.onDimensionsChanged(() => this._onInstanceDimensionsChanged.fire(instance))); + instance.addDisposable(instance.onMaximumDimensionsChanged(() => this._onInstanceMaximumDimensionsChanged.fire(instance))); + instance.addDisposable(instance.onFocus(this._onActiveInstanceChanged.fire, this._onActiveInstanceChanged)); + } + + private _getTabForInstance(instance: ITerminalInstance): ITerminalTab | null { + for (const tab of this._terminalTabs) { + if (tab.terminalInstances.indexOf(instance) !== -1) { + return tab; + } + } + return null; + } + + public showPanel(focus?: boolean): Promise { + return new Promise((complete) => { + const panel = this._panelService.getActivePanel(); + if (!panel || panel.getId() !== TERMINAL_PANEL_ID) { + this._panelService.openPanel(TERMINAL_PANEL_ID, focus); + if (focus) { + // Do the focus call asynchronously as going through the + // command palette will force editor focus + setTimeout(() => { + const instance = this.getActiveInstance(); + if (instance) { + instance.focusWhenReady(true).then(() => complete(undefined)); + } else { + complete(undefined); + } + }, 0); + } else { + complete(undefined); + } + } else { + if (focus) { + // Do the focus call asynchronously as going through the + // command palette will force editor focus + setTimeout(() => { + const instance = this.getActiveInstance(); + if (instance) { + instance.focusWhenReady(true).then(() => complete(undefined)); + } else { + complete(undefined); + } + }, 0); + } else { + complete(undefined); + } + } + return undefined; + }); + } + + private _getIndexFromId(terminalId: number): number { + let terminalIndex = -1; + this.terminalInstances.forEach((terminalInstance, i) => { + if (terminalInstance.id === terminalId) { + terminalIndex = i; + } + }); + if (terminalIndex === -1) { + throw new Error(`Terminal with ID ${terminalId} does not exist (has it already been disposed?)`); + } + return terminalIndex; + } + + public async manageWorkspaceShellPermissions(): Promise { + const allowItem: IQuickPickItem = { label: nls.localize('workbench.action.terminal.allowWorkspaceShell', "Allow Workspace Shell Configuration") }; + const disallowItem: IQuickPickItem = { label: nls.localize('workbench.action.terminal.disallowWorkspaceShell', "Disallow Workspace Shell Configuration") }; + const value = await this._quickInputService.pick([allowItem, disallowItem], { canPickMany: false }); + if (!value) { + return; + } + this.configHelper.setWorkspaceShellAllowed(value === allowItem); + } + + protected async _showTerminalCloseConfirmation(): Promise { + let message: string; + if (this.terminalInstances.length === 1) { + message = nls.localize('terminalService.terminalCloseConfirmationSingular', "There is an active terminal session, do you want to kill it?"); + } else { + message = nls.localize('terminalService.terminalCloseConfirmationPlural', "There are {0} active terminal sessions, do you want to kill them?", this.terminalInstances.length); + } + const res = await this._dialogService.confirm({ + message, + type: 'warning', + }); + return !res.confirmed; + } + + protected _showNotEnoughSpaceToast(): void { + this._notificationService.info(nls.localize('terminal.minWidth', "Not enough space to split terminal.")); + } + + protected _validateShellPaths(label: string, potentialPaths: string[]): Promise<[string, string] | null> { + if (potentialPaths.length === 0) { + return Promise.resolve(null); + } + const current = potentialPaths.shift(); + if (current! === '') { + return this._validateShellPaths(label, potentialPaths); + } + return this._fileService.exists(URI.file(current!)).then(exists => { + if (!exists) { + return this._validateShellPaths(label, potentialPaths); + } + return [label, current] as [string, string]; + }); + } + + public preparePathForTerminalAsync(originalPath: string, executable: string, title: string): Promise { + return new Promise(c => { + if (!executable) { + c(originalPath); + return; + } + + const hasSpace = originalPath.indexOf(' ') !== -1; + + const pathBasename = basename(executable, '.exe'); + const isPowerShell = pathBasename === 'pwsh' || + title === 'pwsh' || + pathBasename === 'powershell' || + title === 'powershell'; + + if (isPowerShell && (hasSpace || originalPath.indexOf('\'') !== -1)) { + c(`& '${originalPath.replace(/'/g, '\'\'')}'`); + return; + } + + if (isWindows) { + // 17063 is the build number where wsl path was introduced. + // Update Windows uriPath to be executed in WSL. + const lowerExecutable = executable.toLowerCase(); + if (this._terminalNativeService.getWindowsBuildNumber() >= 17063 && + (lowerExecutable.indexOf('wsl') !== -1 || (lowerExecutable.indexOf('bash.exe') !== -1 && lowerExecutable.toLowerCase().indexOf('git') === -1))) { + c(this._terminalNativeService.getWslPath(originalPath)); + return; + } else if (hasSpace) { + c('"' + originalPath + '"'); + } else { + c(originalPath); + } + return; + } + c(escapeNonWindowsPath(originalPath)); + }); + } + + public selectDefaultWindowsShell(): Promise { + return this._detectWindowsShells().then(shells => { + const options: IPickOptions = { + placeHolder: nls.localize('terminal.integrated.chooseWindowsShell', "Select your preferred terminal shell, you can change this later in your settings") + }; + const quickPickItems = shells.map((s): IQuickPickItem => { + return { label: s.label, description: s.path }; + }); + return this._quickInputService.pick(quickPickItems, options).then(async value => { + if (!value) { + return undefined; + } + const shell = value.description; + const env = await this._remoteAgentService.getEnvironment(); + let platformKey: string; + if (env) { + platformKey = env.os === OperatingSystem.Windows ? 'windows' : (env.os === OperatingSystem.Macintosh ? 'osx' : 'linux'); + } else { + platformKey = isWindows ? 'windows' : (isMacintosh ? 'osx' : 'linux'); + } + await this._configurationService.updateValue(`terminal.integrated.shell.${platformKey}`, shell, ConfigurationTarget.USER).then(() => shell); + return Promise.resolve(); + }); + }); + } + + private _detectWindowsShells(): Promise { + return new Promise(r => this._onRequestAvailableShells.fire(r)); + } + + public createInstance(container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance { const instance = this._instantiationService.createInstance(TerminalInstance, this._terminalFocusContextKey, this._configHelper, container, shellLaunchConfig); this._onInstanceCreated.fire(instance); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTab.ts b/src/vs/workbench/contrib/terminal/browser/terminalTab.ts index 4b4d548b3e..cc1e0e6620 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTab.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTab.ts @@ -4,13 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import * as aria from 'vs/base/browser/ui/aria/aria'; import * as nls from 'vs/nls'; -import { ITerminalInstance, IShellLaunchConfig, ITerminalTab, Direction, ITerminalService, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IShellLaunchConfig, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { Event, Emitter } from 'vs/base/common/event'; import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { SplitView, Orientation, IView, Sizing } from 'vs/base/browser/ui/splitview/splitview'; import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ITerminalInstance, Direction, ITerminalTab, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; const SPLIT_PANE_MIN_SIZE = 120; const TERMINAL_MIN_USEFUL_SIZE = 250; diff --git a/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts b/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts new file mode 100644 index 0000000000..dc67c979a9 --- /dev/null +++ b/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export interface XTermCore { + _onScroll: IEventEmitter; + _onKey: IEventEmitter<{ key: string }>; + + _charSizeService: { + width: number; + height: number; + }; + + _coreService: { + triggerDataEvent(data: string, wasUserInput?: boolean): void; + }; + + _renderService: { + _renderer: { + _renderLayers: any[]; + }; + _onIntersectionChange: any; + }; + + // TODO: Remove below once a synchronous write API is added + // The below are only used in tests + writeBuffer: string[]; + _innerWrite(): void; +} + +export interface IEventEmitter { + fire(e: T): void; +} diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index e5fde473ef..1447f3474b 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -6,10 +6,9 @@ import * as nls from 'vs/nls'; import { Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { RawContextKey, ContextKeyExpr, IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; -import { FindReplaceState } from 'vs/editor/contrib/find/findState'; import { OperatingSystem } from 'vs/base/common/platform'; import { IOpenFileRequest } from 'vs/platform/windows/common/windows'; @@ -48,7 +47,6 @@ export const NEVER_MEASURE_RENDER_TIME_STORAGE_KEY = 'terminal.integrated.neverM // trying to create the corressponding object on the ext host. export const EXT_HOST_CREATION_DELAY = 100; -export const ITerminalService = createDecorator('terminalService'); export const ITerminalNativeService = createDecorator('terminalNativeService'); export const TerminalCursorStyle = { @@ -100,7 +98,7 @@ export interface ITerminalConfiguration { fontSize: number; letterSpacing: number; lineHeight: number; - setLocaleVariables: boolean; + detectLocale: 'auto' | 'off' | 'on'; scrollback: number; commandsToSkipShell: string[]; cwd: string; @@ -217,94 +215,11 @@ export interface IShellLaunchConfig { hideFromUser?: boolean; } -export interface ITerminalService { - _serviceBrand: any; - - activeTabIndex: number; - configHelper: ITerminalConfigHelper; - terminalInstances: ITerminalInstance[]; - terminalTabs: ITerminalTab[]; - - onActiveTabChanged: Event; - onTabDisposed: Event; - onInstanceCreated: Event; - onInstanceDisposed: Event; - onInstanceProcessIdReady: Event; - onInstanceDimensionsChanged: Event; - onInstanceMaximumDimensionsChanged: Event; - onInstanceRequestSpawnExtHostProcess: Event; - onInstanceRequestStartExtensionTerminal: Event; - onInstancesChanged: Event; - onInstanceTitleChanged: Event; - onActiveInstanceChanged: Event; - onRequestAvailableShells: Event; - - /** - * Creates a terminal. - * @param shell The shell launch configuration to use. - */ - createTerminal(shell?: IShellLaunchConfig): ITerminalInstance; - - /** - * Creates a raw terminal instance, this should not be used outside of the terminal part. - */ - // tslint:disable-next-line: no-dom-globals - createInstance(container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance; - getInstanceFromId(terminalId: number): ITerminalInstance | undefined; - getInstanceFromIndex(terminalIndex: number): ITerminalInstance; - getTabLabels(): string[]; - getActiveInstance(): ITerminalInstance | null; - setActiveInstance(terminalInstance: ITerminalInstance): void; - setActiveInstanceByIndex(terminalIndex: number): void; - getActiveOrCreateInstance(wasNewTerminalAction?: boolean): ITerminalInstance; - splitInstance(instance: ITerminalInstance, shell?: IShellLaunchConfig): ITerminalInstance | null; - - getActiveTab(): ITerminalTab | null; - setActiveTabToNext(): void; - setActiveTabToPrevious(): void; - setActiveTabByIndex(tabIndex: number): void; - - /** - * Fire the onActiveTabChanged event, this will trigger the terminal dropdown to be updated, - * among other things. - */ - refreshActiveTab(): void; - - showPanel(focus?: boolean): Promise; - hidePanel(): void; - focusFindWidget(): Promise; - hideFindWidget(): void; - getFindState(): FindReplaceState; - findNext(): void; - findPrevious(): void; - - selectDefaultWindowsShell(): Promise; - - // tslint:disable-next-line: no-dom-globals - setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; - manageWorkspaceShellPermissions(): void; - - /** - * Takes a path and returns the properly escaped path to send to the terminal. - * On Windows, this included trying to prepare the path for WSL if needed. - * - * @param executable The executable off the shellLaunchConfig - * @param title The terminal's title - * @param path The path to be escaped and formatted. - * @returns An escaped version of the path to be execuded in the terminal. - */ - preparePathForTerminalAsync(path: string, executable: string | undefined, title: string): Promise; - - extHostReady(remoteAuthority: string): void; - requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; - requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void; -} - /** * Provides access to native or electron APIs to other terminal services. */ export interface ITerminalNativeService { - _serviceBrand: any; + _serviceBrand: undefined; readonly linuxDistro: LinuxDistro; @@ -321,32 +236,6 @@ export interface IShellDefinition { path: string; } -export const enum Direction { - Left = 0, - Right = 1, - Up = 2, - Down = 3 -} - -export interface ITerminalTab { - activeInstance: ITerminalInstance | null; - terminalInstances: ITerminalInstance[]; - title: string; - onDisposed: Event; - onInstancesChanged: Event; - - focusPreviousPane(): void; - focusNextPane(): void; - resizePane(direction: Direction): void; - setActiveInstanceByIndex(index: number): void; - // tslint:disable-next-line: no-dom-globals - attachToElement(element: HTMLElement): void; - setVisible(visible: boolean): void; - layout(width: number, height: number): void; - addDisposable(disposable: IDisposable): void; - split(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance | undefined; -} - export interface ITerminalDimensions { /** * The columns of the terminal. @@ -359,302 +248,6 @@ export interface ITerminalDimensions { readonly rows: number; } -interface ISearchOptions { - /** - * Whether the find should be done as a regex. - */ - regex?: boolean; - /** - * Whether only whole words should match. - */ - wholeWord?: boolean; - /** - * Whether find should pay attention to case. - */ - caseSensitive?: boolean; - /** - * Whether the search should start at the current search position (not the next row) - */ - incremental?: boolean; -} - -export interface ITerminalInstance { - /** - * The ID of the terminal instance, this is an arbitrary number only used to identify the - * terminal instance. - */ - readonly id: number; - - readonly cols: number; - readonly rows: number; - readonly maxCols: number; - readonly maxRows: number; - - /** - * The process ID of the shell process, this is undefined when there is no process associated - * with this terminal. - */ - processId: number | undefined; - - /** - * An event that fires when the terminal instance's title changes. - */ - onTitleChanged: Event; - - /** - * An event that fires when the terminal instance is disposed. - */ - onDisposed: Event; - - onFocused: Event; - onProcessIdReady: Event; - onRequestExtHostProcess: Event; - onDimensionsChanged: Event; - onMaximumDimensionsChanged: Event; - - onFocus: Event; - - /** - * Attach a listener to the raw data stream coming from the pty, including ANSI escape - * sequences. - */ - onData: Event; - - /** - * Attach a listener to listen for new lines added to this terminal instance. - * - * @param listener The listener function which takes new line strings added to the terminal, - * excluding ANSI escape sequences. The line event will fire when an LF character is added to - * the terminal (ie. the line is not wrapped). Note that this means that the line data will - * not fire for the last line, until either the line is ended with a LF character of the process - * is exited. The lineData string will contain the fully wrapped line, not containing any LF/CR - * characters. - */ - onLineData: Event; - - /** - * Attach a listener that fires when the terminal's pty process exits. The number in the event - * is the processes' exit code, an exit code of null means the process was killed as a result of - * the ITerminalInstance being disposed. - */ - onExit: Event; - - processReady: Promise; - - /** - * The title of the terminal. This is either title or the process currently running or an - * explicit name given to the terminal instance through the extension API. - */ - readonly title: string; - - /** - * The focus state of the terminal before exiting. - */ - readonly hadFocusOnExit: boolean; - - /** - * False when the title is set by an API or the user. We check this to make sure we - * do not override the title when the process title changes in the terminal. - */ - isTitleSetByProcess: boolean; - - /** - * The shell launch config used to launch the shell. - */ - readonly shellLaunchConfig: IShellLaunchConfig; - - /** - * Whether to disable layout for the terminal. This is useful when the size of the terminal is - * being manipulating (e.g. adding a split pane) and we want the terminal to ignore particular - * resize events. - */ - disableLayout: boolean; - - /** - * An object that tracks when commands are run and enables navigating and selecting between - * them. - */ - readonly commandTracker: ICommandTracker | undefined; - - readonly navigationMode: INavigationMode | undefined; - - /** - * Dispose the terminal instance, removing it from the panel/service and freeing up resources. - * - * @param immediate Whether the kill should be immediate or not. Immediate should only be used - * when VS Code is shutting down or in cases where the terminal dispose was user initiated. - * The immediate===false exists to cover an edge case where the final output of the terminal can - * get cut off. If immediate kill any terminal processes immediately. - */ - dispose(immediate?: boolean): void; - - /** - * Forces the terminal to redraw its viewport. - */ - forceRedraw(): void; - - /** - * Registers a link matcher, allowing custom link patterns to be matched and handled. - * @param regex The regular expression the search for, specifically this searches the - * textContent of the rows. You will want to use \s to match a space ' ' character for example. - * @param handler The callback when the link is called. - * @param matchIndex The index of the link from the regex.match(html) call. This defaults to 0 - * (for regular expressions without capture groups). - * @param validationCallback A callback which can be used to validate the link after it has been - * added to the DOM. - * @return The ID of the new matcher, this can be used to deregister. - */ - registerLinkMatcher(regex: RegExp, handler: (url: string) => void, matchIndex?: number, validationCallback?: (uri: string, callback: (isValid: boolean) => void) => void): number; - - /** - * Deregisters a link matcher if it has been registered. - * @param matcherId The link matcher's ID (returned after register) - * @return Whether a link matcher was found and deregistered. - */ - deregisterLinkMatcher(matcherId: number): void; - - /** - * Check if anything is selected in terminal. - */ - hasSelection(): boolean; - - /** - * Copies the terminal selection to the clipboard. - */ - copySelection(): Promise; - - /** - * Current selection in the terminal. - */ - readonly selection: string | undefined; - - /** - * Clear current selection. - */ - clearSelection(): void; - - /** - * Select all text in the terminal. - */ - selectAll(): void; - - /** - * Find the next instance of the term - */ - findNext(term: string, searchOptions: ISearchOptions): boolean; - - /** - * Find the previous instance of the term - */ - findPrevious(term: string, searchOptions: ISearchOptions): boolean; - - /** - * Notifies the terminal that the find widget's focus state has been changed. - */ - notifyFindWidgetFocusChanged(isFocused: boolean): void; - - /** - * Focuses the terminal instance if it's able to (xterm.js instance exists). - * - * @param focus Force focus even if there is a selection. - */ - focus(force?: boolean): void; - - /** - * Focuses the terminal instance when it's ready (the xterm.js instance is created). Use this - * when the terminal is being shown. - * - * @param focus Force focus even if there is a selection. - */ - focusWhenReady(force?: boolean): Promise; - - /** - * Focuses and pastes the contents of the clipboard into the terminal instance. - */ - paste(): Promise; - - /** - * Send text to the terminal instance. The text is written to the stdin of the underlying pty - * process (shell) of the terminal instance. - * - * @param text The text to send. - * @param addNewLine Whether to add a new line to the text being sent, this is normally - * required to run a command in the terminal. The character(s) added are \n or \r\n - * depending on the platform. This defaults to `true`. - */ - sendText(text: string, addNewLine: boolean): void; - - /** - * Write text directly to the terminal, skipping the process if it exists. - * @param text The text to write. - */ - write(text: string): void; - - /** Scroll the terminal buffer down 1 line. */ - scrollDownLine(): void; - /** Scroll the terminal buffer down 1 page. */ - scrollDownPage(): void; - /** Scroll the terminal buffer to the bottom. */ - scrollToBottom(): void; - /** Scroll the terminal buffer up 1 line. */ - scrollUpLine(): void; - /** Scroll the terminal buffer up 1 page. */ - scrollUpPage(): void; - /** Scroll the terminal buffer to the top. */ - scrollToTop(): void; - - /** - * Clears the terminal buffer, leaving only the prompt line. - */ - clear(): void; - - /** - * Attaches the terminal instance to an element on the DOM, before this is called the terminal - * instance process may run in the background but cannot be displayed on the UI. - * - * @param container The element to attach the terminal instance to. - */ - // tslint:disable-next-line: no-dom-globals - attachToElement(container: HTMLElement): void; - - /** - * Configure the dimensions of the terminal instance. - * - * @param dimension The dimensions of the container. - */ - layout(dimension: { width: number, height: number }): void; - - /** - * Sets whether the terminal instance's element is visible in the DOM. - * - * @param visible Whether the element is visible. - */ - setVisible(visible: boolean): void; - - /** - * Immediately kills the terminal's current pty process and launches a new one to replace it. - * - * @param shell The new launch configuration. - */ - reuseTerminal(shell: IShellLaunchConfig): void; - - /** - * Sets the title of the terminal instance. - */ - setTitle(title: string, eventSource: TitleEventSource): void; - - waitForTitle(): Promise; - - setDimensions(dimensions: ITerminalDimensions): void; - - addDisposable(disposable: IDisposable): void; - - toggleEscapeSequenceLogging(): void; - - getInitialCwd(): Promise; - getCwd(): Promise; -} - export interface ICommandTracker { scrollToPreviousCommand(): void; scrollToNextCommand(): void; @@ -813,3 +406,69 @@ export interface ITerminalChildProcess { getCwd(): Promise; getLatency(): Promise; } + +export const enum TERMINAL_COMMAND_ID { + FIND_NEXT = 'workbench.action.terminal.findNext', + FIND_NEXT_TERMINAL_FOCUS = 'workbench.action.terminal.findNextTerminalFocus', + FIND_PREVIOUS = 'workbench.action.terminal.findPrevious', + FIND_PREVIOUS_TERMINAL_FOCUS = 'workbench.action.terminal.findPreviousTerminalFocus', + TOGGLE = 'workbench.action.terminal.toggleTerminal', + KILL = 'workbench.action.terminal.kill', + QUICK_KILL = 'workbench.action.terminal.quickKill', + COPY_SELECTION = 'workbench.action.terminal.copySelection', + SELECT_ALL = 'workbench.action.terminal.selectAll', + DELETE_WORD_LEFT = 'workbench.action.terminal.deleteWordLeft', + DELETE_WORD_RIGHT = 'workbench.action.terminal.deleteWordRight', + DELETE_TO_LINE_START = 'workbench.action.terminal.deleteToLineStart', + MOVE_TO_LINE_START = 'workbench.action.terminal.moveToLineStart', + MOVE_TO_LINE_END = 'workbench.action.terminal.moveToLineEnd', + NEW = 'workbench.action.terminal.new', + NEW_LOCAL = 'workbench.action.terminal.newLocal', + NEW_IN_ACTIVE_WORKSPACE = 'workbench.action.terminal.newInActiveWorkspace', + SPLIT = 'workbench.action.terminal.split', + SPLIT_IN_ACTIVE_WORKSPACE = 'workbench.action.terminal.splitInActiveWorkspace', + FOCUS_PREVIOUS_PANE = 'workbench.action.terminal.focusPreviousPane', + FOCUS_NEXT_PANE = 'workbench.action.terminal.focusNextPane', + RESIZE_PANE_LEFT = 'workbench.action.terminal.resizePaneLeft', + RESIZE_PANE_RIGHT = 'workbench.action.terminal.resizePaneRight', + RESIZE_PANE_UP = 'workbench.action.terminal.resizePaneUp', + RESIZE_PANE_DOWN = 'workbench.action.terminal.resizePaneDown', + FOCUS = 'workbench.action.terminal.focus', + FOCUS_NEXT = 'workbench.action.terminal.focusNext', + FOCUS_PREVIOUS = 'workbench.action.terminal.focusPrevious', + PASTE = 'workbench.action.terminal.paste', + SELECT_DEFAULT_SHELL = 'workbench.action.terminal.selectDefaultShell', + RUN_SELECTED_TEXT = 'workbench.action.terminal.runSelectedText', + RUN_ACTIVE_FILE = 'workbench.action.terminal.runActiveFile', + SWITCH_TERMINAL = 'workbench.action.terminal.switchTerminal', + SCROLL_DOWN_LINE = 'workbench.action.terminal.scrollDown', + SCROLL_DOWN_PAGE = 'workbench.action.terminal.scrollDownPage', + SCROLL_TO_BOTTOM = 'workbench.action.terminal.scrollToBottom', + SCROLL_UP_LINE = 'workbench.action.terminal.scrollUp', + SCROLL_UP_PAGE = 'workbench.action.terminal.scrollUpPage', + SCROLL_TO_TOP = 'workbench.action.terminal.scrollToTop', + CLEAR = 'workbench.action.terminal.clear', + CLEAR_SELECTION = 'workbench.action.terminal.clearSelection', + MANAGE_WORKSPACE_SHELL_PERMISSIONS = 'workbench.action.terminal.manageWorkspaceShellPermissions', + RENAME = 'workbench.action.terminal.rename', + FIND_WIDGET_FOCUS = 'workbench.action.terminal.focusFindWidget', + FIND_WIDGET_HIDE = 'workbench.action.terminal.hideFindWidget', + QUICK_OPEN_TERM = 'workbench.action.quickOpenTerm', + SCROLL_TO_PREVIOUS_COMMAND = 'workbench.action.terminal.scrollToPreviousCommand', + SCROLL_TO_NEXT_COMMAND = 'workbench.action.terminal.scrollToNextCommand', + SELECT_TO_PREVIOUS_COMMAND = 'workbench.action.terminal.selectToPreviousCommand', + SELECT_TO_NEXT_COMMAND = 'workbench.action.terminal.selectToNextCommand', + SELECT_TO_PREVIOUS_LINE = 'workbench.action.terminal.selectToPreviousLine', + SELECT_TO_NEXT_LINE = 'workbench.action.terminal.selectToNextLine', + TOGGLE_ESCAPE_SEQUENCE_LOGGING = 'toggleEscapeSequenceLogging', + SEND_SEQUENCE = 'workbench.action.terminal.sendSequence', + TOGGLE_FIND_REGEX = 'workbench.action.terminal.toggleFindRegex', + TOGGLE_FIND_WHOLE_WORD = 'workbench.action.terminal.toggleFindWholeWord', + TOGGLE_FIND_CASE_SENSITIVE = 'workbench.action.terminal.toggleFindCaseSensitive', + 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' +} diff --git a/src/vs/workbench/contrib/terminal/common/terminalCommands.ts b/src/vs/workbench/contrib/terminal/common/terminalCommands.ts deleted file mode 100644 index 6cbf276e25..0000000000 --- a/src/vs/workbench/contrib/terminal/common/terminalCommands.ts +++ /dev/null @@ -1,96 +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 { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { ITerminalService } from 'vs/workbench/contrib/terminal/common/terminal'; - -export const enum TERMINAL_COMMAND_ID { - FIND_NEXT = 'workbench.action.terminal.findNext', - FIND_NEXT_TERMINAL_FOCUS = 'workbench.action.terminal.findNextTerminalFocus', - FIND_PREVIOUS = 'workbench.action.terminal.findPrevious', - FIND_PREVIOUS_TERMINAL_FOCUS = 'workbench.action.terminal.findPreviousTerminalFocus', - TOGGLE = 'workbench.action.terminal.toggleTerminal', - KILL = 'workbench.action.terminal.kill', - QUICK_KILL = 'workbench.action.terminal.quickKill', - COPY_SELECTION = 'workbench.action.terminal.copySelection', - SELECT_ALL = 'workbench.action.terminal.selectAll', - DELETE_WORD_LEFT = 'workbench.action.terminal.deleteWordLeft', - DELETE_WORD_RIGHT = 'workbench.action.terminal.deleteWordRight', - DELETE_TO_LINE_START = 'workbench.action.terminal.deleteToLineStart', - MOVE_TO_LINE_START = 'workbench.action.terminal.moveToLineStart', - MOVE_TO_LINE_END = 'workbench.action.terminal.moveToLineEnd', - NEW = 'workbench.action.terminal.new', - NEW_LOCAL = 'workbench.action.terminal.newLocal', - NEW_IN_ACTIVE_WORKSPACE = 'workbench.action.terminal.newInActiveWorkspace', - SPLIT = 'workbench.action.terminal.split', - SPLIT_IN_ACTIVE_WORKSPACE = 'workbench.action.terminal.splitInActiveWorkspace', - FOCUS_PREVIOUS_PANE = 'workbench.action.terminal.focusPreviousPane', - FOCUS_NEXT_PANE = 'workbench.action.terminal.focusNextPane', - RESIZE_PANE_LEFT = 'workbench.action.terminal.resizePaneLeft', - RESIZE_PANE_RIGHT = 'workbench.action.terminal.resizePaneRight', - RESIZE_PANE_UP = 'workbench.action.terminal.resizePaneUp', - RESIZE_PANE_DOWN = 'workbench.action.terminal.resizePaneDown', - FOCUS = 'workbench.action.terminal.focus', - FOCUS_NEXT = 'workbench.action.terminal.focusNext', - FOCUS_PREVIOUS = 'workbench.action.terminal.focusPrevious', - PASTE = 'workbench.action.terminal.paste', - SELECT_DEFAULT_SHELL = 'workbench.action.terminal.selectDefaultShell', - RUN_SELECTED_TEXT = 'workbench.action.terminal.runSelectedText', - RUN_ACTIVE_FILE = 'workbench.action.terminal.runActiveFile', - SWITCH_TERMINAL = 'workbench.action.terminal.switchTerminal', - SCROLL_DOWN_LINE = 'workbench.action.terminal.scrollDown', - SCROLL_DOWN_PAGE = 'workbench.action.terminal.scrollDownPage', - SCROLL_TO_BOTTOM = 'workbench.action.terminal.scrollToBottom', - SCROLL_UP_LINE = 'workbench.action.terminal.scrollUp', - SCROLL_UP_PAGE = 'workbench.action.terminal.scrollUpPage', - SCROLL_TO_TOP = 'workbench.action.terminal.scrollToTop', - CLEAR = 'workbench.action.terminal.clear', - CLEAR_SELECTION = 'workbench.action.terminal.clearSelection', - MANAGE_WORKSPACE_SHELL_PERMISSIONS = 'workbench.action.terminal.manageWorkspaceShellPermissions', - RENAME = 'workbench.action.terminal.rename', - FIND_WIDGET_FOCUS = 'workbench.action.terminal.focusFindWidget', - FIND_WIDGET_HIDE = 'workbench.action.terminal.hideFindWidget', - QUICK_OPEN_TERM = 'workbench.action.quickOpenTerm', - SCROLL_TO_PREVIOUS_COMMAND = 'workbench.action.terminal.scrollToPreviousCommand', - SCROLL_TO_NEXT_COMMAND = 'workbench.action.terminal.scrollToNextCommand', - SELECT_TO_PREVIOUS_COMMAND = 'workbench.action.terminal.selectToPreviousCommand', - SELECT_TO_NEXT_COMMAND = 'workbench.action.terminal.selectToNextCommand', - SELECT_TO_PREVIOUS_LINE = 'workbench.action.terminal.selectToPreviousLine', - SELECT_TO_NEXT_LINE = 'workbench.action.terminal.selectToNextLine', - TOGGLE_ESCAPE_SEQUENCE_LOGGING = 'toggleEscapeSequenceLogging', - SEND_SEQUENCE = 'workbench.action.terminal.sendSequence', - TOGGLE_FIND_REGEX = 'workbench.action.terminal.toggleFindRegex', - TOGGLE_FIND_WHOLE_WORD = 'workbench.action.terminal.toggleFindWholeWord', - TOGGLE_FIND_CASE_SENSITIVE = 'workbench.action.terminal.toggleFindCaseSensitive', - 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 { - registerOpenTerminalAtIndexCommands(); -} - -function registerOpenTerminalAtIndexCommands(): void { - for (let i = 0; i < 9; i++) { - const terminalIndex = i; - const visibleIndex = i + 1; - - KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: `workbench.action.terminal.focusAtIndex${visibleIndex}`, - weight: KeybindingWeight.WorkbenchContrib, - when: undefined, - primary: 0, - handler: accessor => { - const terminalService = accessor.get(ITerminalService); - terminalService.setActiveInstanceByIndex(terminalIndex); - return terminalService.showPanel(true); - } - }); - } -} diff --git a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index e926c53ae5..0e23de9a2b 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -51,13 +51,13 @@ function _mergeEnvironmentValue(env: ITerminalEnvironment, key: string, value: s } } -export function addTerminalEnvironmentKeys(env: platform.IProcessEnvironment, version: string | undefined, locale: string | undefined, setLocaleVariables: boolean): void { +export function addTerminalEnvironmentKeys(env: platform.IProcessEnvironment, version: string | undefined, locale: string | undefined, detectLocale: 'auto' | 'off' | 'on'): void { env['TERM_PROGRAM'] = 'vscode'; if (version) { env['TERM_PROGRAM_VERSION'] = version; } - if (setLocaleVariables) { - env['LANG'] = _getLangEnvVariable(locale); + if (shouldSetLangEnvVariable(env, detectLocale)) { + env['LANG'] = getLangEnvVariable(locale); } env['COLORTERM'] = 'truecolor'; } @@ -88,37 +88,87 @@ function resolveConfigurationVariables(configurationResolverService: IConfigurat return env; } -function _getLangEnvVariable(locale?: string) { +export function shouldSetLangEnvVariable(env: platform.IProcessEnvironment, detectLocale: 'auto' | 'off' | 'on'): boolean { + if (detectLocale === 'on') { + return true; + } + if (detectLocale === 'auto') { + return !env['LANG'] || env['LANG'].search(/\.UTF\-8$/) === -1; + } + return false; // 'off' +} + +export function getLangEnvVariable(locale?: string): string { const parts = locale ? locale.split('-') : []; const n = parts.length; if (n === 0) { - // Fallback to en_US to prevent possible encoding issues. + // Fallback to en_US if the locale is unknown return 'en_US.UTF-8'; } if (n === 1) { - // app.getLocale can return just a language without a variant, fill in the variant for - // supported languages as many shells expect a 2-part locale. + // The local may only contain the language, not the variant, if this is the case guess the + // variant such that it can be used as a valid $LANG variable. The language variant chosen + // is the original and/or most prominent with help from + // https://stackoverflow.com/a/2502675/1156119 + // The list of locales was generated by running `locale -a` on macOS const languageVariants: { [key: string]: string } = { + af: 'ZA', + am: 'ET', + be: 'BY', + bg: 'BG', + ca: 'ES', cs: 'CZ', + da: 'DK', + // de: 'AT', + // de: 'CH', de: 'DE', + el: 'GR', + // en: 'AU', + // en: 'CA', + // en: 'GB', + // en: 'IE', + // en: 'NZ', en: 'US', es: 'ES', + et: 'EE', + eu: 'ES', fi: 'FI', + // fr: 'BE', + // fr: 'CA', + // fr: 'CH', fr: 'FR', + he: 'IL', + hr: 'HR', hu: 'HU', + hy: 'AM', + is: 'IS', + // it: 'CH', it: 'IT', ja: 'JP', + kk: 'KZ', ko: 'KR', + lt: 'LT', + // nl: 'BE', + nl: 'NL', + no: 'NO', pl: 'PL', + pt: 'BR', + // pt: 'PT', + ro: 'RO', ru: 'RU', sk: 'SK', - zh: 'CN' + sl: 'SI', + sr: 'YU', + sv: 'SE', + tr: 'TR', + uk: 'UA', + zh: 'CN', }; if (parts[0] in languageVariants) { parts.push(languageVariants[parts[0]]); } } else { - // Ensure the variant is uppercase + // Ensure the variant is uppercase to be a valid $LANG parts[1] = parts[1].toUpperCase(); } return parts.join('_') + '.UTF-8'; @@ -294,7 +344,7 @@ export function createTerminalEnvironment( configurationResolverService: IConfigurationResolverService | undefined, isWorkspaceShellAllowed: boolean, version: string | undefined, - setLocaleVariables: boolean, + detectLocale: 'auto' | 'off' | 'on', baseEnv: platform.IProcessEnvironment ): platform.IProcessEnvironment { // Create a terminal environment based on settings, launch config and permissions @@ -329,7 +379,7 @@ export function createTerminalEnvironment( mergeEnvironments(env, shellLaunchConfig.env); // Adding other env keys necessary to create the process - addTerminalEnvironmentKeys(env, version, platform.locale, setLocaleVariables); + addTerminalEnvironmentKeys(env, version, platform.locale, detectLocale); } return env; } diff --git a/src/vs/workbench/contrib/terminal/common/terminalMenu.ts b/src/vs/workbench/contrib/terminal/common/terminalMenu.ts index 5e89a58075..8d79b06022 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalMenu.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalMenu.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; -import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; +import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; export function setupTerminalMenu() { diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts deleted file mode 100644 index ac31ebbc6e..0000000000 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ /dev/null @@ -1,595 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as nls from 'vs/nls'; -import { 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, 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'; -import { INotificationService } from 'vs/platform/notification/common/notification'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { IFileService } from 'vs/platform/files/common/files'; -import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -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 { 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; - - protected _isShuttingDown: boolean; - protected _terminalFocusContextKey: IContextKey; - protected _findWidgetVisible: IContextKey; - protected _terminalTabs: ITerminalTab[] = []; - protected _backgroundedTerminalInstances: ITerminalInstance[] = []; - protected get _terminalInstances(): ITerminalInstance[] { - return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), []); - } - private _findState: FindReplaceState; - private _extHostsReady: { [authority: string]: IExtHostReadyEntry | undefined } = {}; - private _activeTabIndex: number; - - public get activeTabIndex(): number { return this._activeTabIndex; } - public get terminalInstances(): ITerminalInstance[] { return this._terminalInstances; } - public get terminalTabs(): ITerminalTab[] { return this._terminalTabs; } - - protected readonly _onActiveTabChanged = new Emitter(); - public get onActiveTabChanged(): Event { return this._onActiveTabChanged.event; } - protected readonly _onInstanceCreated = new Emitter(); - public get onInstanceCreated(): Event { return this._onInstanceCreated.event; } - protected readonly _onInstanceDisposed = new Emitter(); - public get onInstanceDisposed(): Event { return this._onInstanceDisposed.event; } - protected readonly _onInstanceProcessIdReady = new Emitter(); - public get onInstanceProcessIdReady(): Event { return this._onInstanceProcessIdReady.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(); - public get onInstanceMaximumDimensionsChanged(): Event { return this._onInstanceMaximumDimensionsChanged.event; } - protected readonly _onInstancesChanged = new Emitter(); - public get onInstancesChanged(): Event { return this._onInstancesChanged.event; } - protected readonly _onInstanceTitleChanged = new Emitter(); - public get onInstanceTitleChanged(): Event { return this._onInstanceTitleChanged.event; } - protected readonly _onActiveInstanceChanged = new Emitter(); - public get onActiveInstanceChanged(): Event { return this._onActiveInstanceChanged.event; } - protected readonly _onTabDisposed = new Emitter(); - public get onTabDisposed(): Event { return this._onTabDisposed.event; } - protected readonly _onRequestAvailableShells = new Emitter(); - public get onRequestAvailableShells(): Event { return this._onRequestAvailableShells.event; } - - public abstract get configHelper(): ITerminalConfigHelper; - - constructor( - @IContextKeyService private readonly _contextKeyService: IContextKeyService, - @IPanelService protected readonly _panelService: IPanelService, - @ILifecycleService readonly lifecycleService: ILifecycleService, - @IStorageService protected readonly _storageService: IStorageService, - @INotificationService protected readonly _notificationService: INotificationService, - @IDialogService private readonly _dialogService: IDialogService, - @IExtensionService private readonly _extensionService: IExtensionService, - @IFileService protected readonly _fileService: IFileService, - @IRemoteAgentService readonly _remoteAgentService: IRemoteAgentService, - @ITerminalNativeService private readonly _terminalNativeService: ITerminalNativeService, - @IQuickInputService private readonly _quickInputService: IQuickInputService, - @IConfigurationService private readonly _configurationService: IConfigurationService - ) { - this._activeTabIndex = 0; - this._isShuttingDown = false; - this._findState = new FindReplaceState(); - lifecycleService.onBeforeShutdown(event => event.veto(this._onBeforeShutdown())); - lifecycleService.onShutdown(() => this._onShutdown()); - this._terminalNativeService.onOpenFileRequest(e => this._onOpenFileRequest(e)); - this._terminalNativeService.onOsResume(() => this._onOsResume()); - this._terminalFocusContextKey = KEYBINDING_CONTEXT_TERMINAL_FOCUS.bindTo(this._contextKeyService); - this._findWidgetVisible = KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE.bindTo(this._contextKeyService); - this.onTabDisposed(tab => this._removeTab(tab)); - this.onActiveTabChanged(() => { - const instance = this.getActiveInstance(); - this._onActiveInstanceChanged.fire(instance ? instance : undefined); - }); - - this._handleContextKeys(); - } - - private _handleContextKeys(): void { - const terminalIsOpenContext = KEYBINDING_CONTEXT_TERMINAL_IS_OPEN.bindTo(this._contextKeyService); - - const updateTerminalContextKeys = () => { - terminalIsOpenContext.set(this.terminalInstances.length > 0); - }; - - this.onInstancesChanged(() => updateTerminalContextKeys()); - } - - protected abstract _showBackgroundTerminal(instance: ITerminalInstance): void; - - public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance; - // tslint:disable-next-line: no-dom-globals - public abstract createInstance(container: HTMLElement, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance; - // tslint:disable-next-line: no-dom-globals - public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; - - public getActiveOrCreateInstance(wasNewTerminalAction?: boolean): ITerminalInstance { - const activeInstance = this.getActiveInstance(); - return activeInstance ? activeInstance : this.createTerminal(undefined, wasNewTerminalAction); - } - - 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 firing - // the event to spawn the ext host process - const conn = this._remoteAgentService.getConnection(); - const remoteAuthority = conn ? conn.remoteAuthority : 'null'; - await this._whenExtHostReady(remoteAuthority); - this._onInstanceRequestSpawnExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, isWorkspaceShellAllowed }); - }); - } - - public requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void { - this._onInstanceRequestStartExtensionTerminal.fire({ proxy, cols, rows }); - } - - 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 { - if (this.terminalInstances.length === 0) { - // No terminal instances, don't veto - return false; - } - - if (this.configHelper.config.confirmOnExit) { - // veto if configured to show confirmation and the user choosed not to exit - return this._showTerminalCloseConfirmation().then(veto => { - if (!veto) { - this._isShuttingDown = true; - } - return veto; - }); - } - - this._isShuttingDown = true; - - return false; - } - - private _onShutdown(): void { - // Dispose of all instances - this.terminalInstances.forEach(instance => instance.dispose(true)); - } - - private _onOpenFileRequest(request: IOpenFileRequest): void { - // if the request to open files is coming in from the integrated terminal (identified though - // the termProgram variable) and we are instructed to wait for editors close, wait for the - // marker file to get deleted and then focus back to the integrated terminal. - if (request.termProgram === 'vscode' && request.filesToWait) { - const waitMarkerFileUri = URI.revive(request.filesToWait.waitMarkerFileUri); - this._terminalNativeService.whenFileDeleted(waitMarkerFileUri).then(() => { - if (this.terminalInstances.length > 0) { - const terminal = this.getActiveInstance(); - if (terminal) { - terminal.focus(); - } - } - }); - } - } - - private _onOsResume(): void { - const activeTab = this.getActiveTab(); - if (!activeTab) { - return; - } - activeTab.terminalInstances.forEach(instance => instance.forceRedraw()); - } - - public getTabLabels(): string[] { - return this._terminalTabs.filter(tab => tab.terminalInstances.length > 0).map((tab, index) => `${index + 1}: ${tab.title ? tab.title : ''}`); - } - - public getFindState(): FindReplaceState { - return this._findState; - } - - private _removeTab(tab: ITerminalTab): void { - // Get the index of the tab and remove it from the list - const index = this._terminalTabs.indexOf(tab); - const wasActiveTab = tab === this.getActiveTab(); - if (index !== -1) { - this._terminalTabs.splice(index, 1); - } - - // Adjust focus if the tab was active - if (wasActiveTab && this._terminalTabs.length > 0) { - // TODO: Only focus the new tab if the removed tab had focus? - // const hasFocusOnExit = tab.activeInstance.hadFocusOnExit; - const newIndex = index < this._terminalTabs.length ? index : this._terminalTabs.length - 1; - this.setActiveTabByIndex(newIndex); - const activeInstance = this.getActiveInstance(); - if (activeInstance) { - activeInstance.focus(true); - } - } - - // Hide the panel if there are no more instances, provided that VS Code is not shutting - // down. When shutting down the panel is locked in place so that it is restored upon next - // launch. - if (this._terminalTabs.length === 0 && !this._isShuttingDown) { - this.hidePanel(); - this._onActiveInstanceChanged.fire(undefined); - } - - // Fire events - this._onInstancesChanged.fire(); - if (wasActiveTab) { - this._onActiveTabChanged.fire(); - } - } - - public refreshActiveTab(): void { - // Fire active instances changed - this._onActiveTabChanged.fire(); - } - - public getActiveTab(): ITerminalTab | null { - if (this._activeTabIndex < 0 || this._activeTabIndex >= this._terminalTabs.length) { - return null; - } - return this._terminalTabs[this._activeTabIndex]; - } - - public getActiveInstance(): ITerminalInstance | null { - const tab = this.getActiveTab(); - if (!tab) { - return null; - } - return tab.activeInstance; - } - - public getInstanceFromId(terminalId: number): ITerminalInstance | undefined { - let bgIndex = -1; - this._backgroundedTerminalInstances.forEach((terminalInstance, i) => { - if (terminalInstance.id === terminalId) { - bgIndex = i; - } - }); - if (bgIndex !== -1) { - return this._backgroundedTerminalInstances[bgIndex]; - } - try { - return this.terminalInstances[this._getIndexFromId(terminalId)]; - } catch { - return undefined; - } - } - - public getInstanceFromIndex(terminalIndex: number): ITerminalInstance { - return this.terminalInstances[terminalIndex]; - } - - public setActiveInstance(terminalInstance: ITerminalInstance): void { - // If this was a hideFromUser terminal created by the API this was triggered by show, - // in which case we need to create the terminal tab - if (terminalInstance.shellLaunchConfig.hideFromUser) { - this._showBackgroundTerminal(terminalInstance); - } - this.setActiveInstanceByIndex(this._getIndexFromId(terminalInstance.id)); - } - - public setActiveTabByIndex(tabIndex: number): void { - if (tabIndex >= this._terminalTabs.length) { - return; - } - - const didTabChange = this._activeTabIndex !== tabIndex; - this._activeTabIndex = tabIndex; - - this._terminalTabs.forEach((t, i) => t.setVisible(i === this._activeTabIndex)); - if (didTabChange) { - this._onActiveTabChanged.fire(); - } - } - - private _getInstanceFromGlobalInstanceIndex(index: number): { tab: ITerminalTab, tabIndex: number, instance: ITerminalInstance, localInstanceIndex: number } | null { - let currentTabIndex = 0; - while (index >= 0 && currentTabIndex < this._terminalTabs.length) { - const tab = this._terminalTabs[currentTabIndex]; - const count = tab.terminalInstances.length; - if (index < count) { - return { - tab, - tabIndex: currentTabIndex, - instance: tab.terminalInstances[index], - localInstanceIndex: index - }; - } - index -= count; - currentTabIndex++; - } - return null; - } - - public setActiveInstanceByIndex(terminalIndex: number): void { - const query = this._getInstanceFromGlobalInstanceIndex(terminalIndex); - if (!query) { - return; - } - - query.tab.setActiveInstanceByIndex(query.localInstanceIndex); - const didTabChange = this._activeTabIndex !== query.tabIndex; - this._activeTabIndex = query.tabIndex; - this._terminalTabs.forEach((t, i) => t.setVisible(i === query.tabIndex)); - - // Only fire the event if there was a change - if (didTabChange) { - this._onActiveTabChanged.fire(); - } - } - - public setActiveTabToNext(): void { - if (this._terminalTabs.length <= 1) { - return; - } - let newIndex = this._activeTabIndex + 1; - if (newIndex >= this._terminalTabs.length) { - newIndex = 0; - } - this.setActiveTabByIndex(newIndex); - } - - public setActiveTabToPrevious(): void { - if (this._terminalTabs.length <= 1) { - return; - } - let newIndex = this._activeTabIndex - 1; - if (newIndex < 0) { - newIndex = this._terminalTabs.length - 1; - } - this.setActiveTabByIndex(newIndex); - } - - public splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfig: IShellLaunchConfig = {}): ITerminalInstance | null { - const tab = this._getTabForInstance(instanceToSplit); - if (!tab) { - return null; - } - - const instance = tab.split(this._terminalFocusContextKey, this.configHelper, shellLaunchConfig); - if (!instance) { - this._showNotEnoughSpaceToast(); - return null; - } - - this._initInstanceListeners(instance); - this._onInstancesChanged.fire(); - - this._terminalTabs.forEach((t, i) => t.setVisible(i === this._activeTabIndex)); - return instance; - } - - protected _initInstanceListeners(instance: ITerminalInstance): void { - instance.addDisposable(instance.onDisposed(this._onInstanceDisposed.fire, this._onInstanceDisposed)); - instance.addDisposable(instance.onTitleChanged(this._onInstanceTitleChanged.fire, this._onInstanceTitleChanged)); - instance.addDisposable(instance.onProcessIdReady(this._onInstanceProcessIdReady.fire, this._onInstanceProcessIdReady)); - instance.addDisposable(instance.onDimensionsChanged(() => this._onInstanceDimensionsChanged.fire(instance))); - instance.addDisposable(instance.onMaximumDimensionsChanged(() => this._onInstanceMaximumDimensionsChanged.fire(instance))); - instance.addDisposable(instance.onFocus(this._onActiveInstanceChanged.fire, this._onActiveInstanceChanged)); - } - - private _getTabForInstance(instance: ITerminalInstance): ITerminalTab | null { - for (const tab of this._terminalTabs) { - if (tab.terminalInstances.indexOf(instance) !== -1) { - return tab; - } - } - return null; - } - - public showPanel(focus?: boolean): Promise { - return new Promise((complete) => { - const panel = this._panelService.getActivePanel(); - if (!panel || panel.getId() !== TERMINAL_PANEL_ID) { - this._panelService.openPanel(TERMINAL_PANEL_ID, focus); - if (focus) { - // Do the focus call asynchronously as going through the - // command palette will force editor focus - setTimeout(() => { - const instance = this.getActiveInstance(); - if (instance) { - instance.focusWhenReady(true).then(() => complete(undefined)); - } else { - complete(undefined); - } - }, 0); - } else { - complete(undefined); - } - } else { - if (focus) { - // Do the focus call asynchronously as going through the - // command palette will force editor focus - setTimeout(() => { - const instance = this.getActiveInstance(); - if (instance) { - instance.focusWhenReady(true).then(() => complete(undefined)); - } else { - complete(undefined); - } - }, 0); - } else { - complete(undefined); - } - } - return undefined; - }); - } - - public abstract hidePanel(): void; - - public abstract focusFindWidget(): Promise; - public abstract hideFindWidget(): void; - - public abstract findNext(): void; - public abstract findPrevious(): void; - - private _getIndexFromId(terminalId: number): number { - let terminalIndex = -1; - this.terminalInstances.forEach((terminalInstance, i) => { - if (terminalInstance.id === terminalId) { - terminalIndex = i; - } - }); - if (terminalIndex === -1) { - throw new Error(`Terminal with ID ${terminalId} does not exist (has it already been disposed?)`); - } - return terminalIndex; - } - - public async manageWorkspaceShellPermissions(): Promise { - const allowItem: IQuickPickItem = { label: nls.localize('workbench.action.terminal.allowWorkspaceShell', "Allow Workspace Shell Configuration") }; - const disallowItem: IQuickPickItem = { label: nls.localize('workbench.action.terminal.disallowWorkspaceShell', "Disallow Workspace Shell Configuration") }; - const value = await this._quickInputService.pick([allowItem, disallowItem], { canPickMany: false }); - if (!value) { - return; - } - this.configHelper.setWorkspaceShellAllowed(value === allowItem); - } - - protected async _showTerminalCloseConfirmation(): Promise { - let message: string; - if (this.terminalInstances.length === 1) { - message = nls.localize('terminalService.terminalCloseConfirmationSingular', "There is an active terminal session, do you want to kill it?"); - } else { - message = nls.localize('terminalService.terminalCloseConfirmationPlural', "There are {0} active terminal sessions, do you want to kill them?", this.terminalInstances.length); - } - const res = await this._dialogService.confirm({ - message, - type: 'warning', - }); - return !res.confirmed; - } - - protected _showNotEnoughSpaceToast(): void { - this._notificationService.info(nls.localize('terminal.minWidth', "Not enough space to split terminal.")); - } - - protected _validateShellPaths(label: string, potentialPaths: string[]): Promise<[string, string] | null> { - if (potentialPaths.length === 0) { - return Promise.resolve(null); - } - const current = potentialPaths.shift(); - if (current! === '') { - return this._validateShellPaths(label, potentialPaths); - } - return this._fileService.exists(URI.file(current!)).then(exists => { - if (!exists) { - return this._validateShellPaths(label, potentialPaths); - } - return [label, current] as [string, string]; - }); - } - - public preparePathForTerminalAsync(originalPath: string, executable: string, title: string): Promise { - return new Promise(c => { - if (!executable) { - c(originalPath); - return; - } - - const hasSpace = originalPath.indexOf(' ') !== -1; - - const pathBasename = basename(executable, '.exe'); - const isPowerShell = pathBasename === 'pwsh' || - title === 'pwsh' || - pathBasename === 'powershell' || - title === 'powershell'; - - if (isPowerShell && (hasSpace || originalPath.indexOf('\'') !== -1)) { - c(`& '${originalPath.replace(/'/g, '\'\'')}'`); - return; - } - - if (isWindows) { - // 17063 is the build number where wsl path was introduced. - // Update Windows uriPath to be executed in WSL. - const lowerExecutable = executable.toLowerCase(); - if (this._terminalNativeService.getWindowsBuildNumber() >= 17063 && - (lowerExecutable.indexOf('wsl') !== -1 || (lowerExecutable.indexOf('bash.exe') !== -1 && lowerExecutable.toLowerCase().indexOf('git') === -1))) { - c(this._terminalNativeService.getWslPath(originalPath)); - return; - } else if (hasSpace) { - c('"' + originalPath + '"'); - } else { - c(originalPath); - } - return; - } - c(escapeNonWindowsPath(originalPath)); - }); - } - - public selectDefaultWindowsShell(): Promise { - return this._detectWindowsShells().then(shells => { - const options: IPickOptions = { - placeHolder: nls.localize('terminal.integrated.chooseWindowsShell', "Select your preferred terminal shell, you can change this later in your settings") - }; - const quickPickItems = shells.map(s => { - return { label: s.label, description: s.path }; - }); - return this._quickInputService.pick(quickPickItems, options).then(async value => { - if (!value) { - return undefined; - } - const shell = value.description; - const env = await this._remoteAgentService.getEnvironment(); - let platformKey: string; - if (env) { - platformKey = env.os === OperatingSystem.Windows ? 'windows' : (env.os === OperatingSystem.Macintosh ? 'osx' : 'linux'); - } else { - platformKey = isWindows ? 'windows' : (isMacintosh ? 'osx' : 'linux'); - } - await this._configurationService.updateValue(`terminal.integrated.shell.${platformKey}`, shell, ConfigurationTarget.USER).then(() => shell); - return Promise.resolve(); - }); - }); - } - - private _detectWindowsShells(): Promise { - return new Promise(r => this._onRequestAvailableShells.fire(r)); - } -} diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts index 377f3fbbd1..48b70035d4 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts @@ -3,9 +3,9 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { ITerminalInstance, IWindowsShellHelper, IShellLaunchConfig, ITerminalChildProcess, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY } from 'vs/workbench/contrib/terminal/common/terminal'; -import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/node/windowsShellHelper'; +import { ITerminalInstanceService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { IWindowsShellHelper, IShellLaunchConfig, ITerminalChildProcess, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY } from 'vs/workbench/contrib/terminal/common/terminal'; +import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/electron-browser/windowsShellHelper'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IProcessEnvironment, platform, Platform } from 'vs/base/common/platform'; import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess'; @@ -27,7 +27,7 @@ let WebLinksAddon: typeof XTermWebLinksAddon; let SearchAddon: typeof XTermSearchAddon; export class TerminalInstanceService implements ITerminalInstanceService { - public _serviceBrand: any; + public _serviceBrand: undefined; constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeService.ts index 9fe77411fc..5fa271ddcc 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeService.ts @@ -13,11 +13,11 @@ import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/termi import { execFile } from 'child_process'; import { Emitter, Event } from 'vs/base/common/event'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { registerRemoteContributions } from 'vs/workbench/contrib/terminal/node/terminalRemote'; +import { registerRemoteContributions } from 'vs/workbench/contrib/terminal/electron-browser/terminalRemote'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; export class TerminalNativeService implements ITerminalNativeService { - public _serviceBrand: any; + public _serviceBrand: undefined; public get linuxDistro(): LinuxDistro { return linuxDistro; } @@ -78,4 +78,4 @@ export class TerminalNativeService implements ITerminalNativeService { public getWindowsBuildNumber(): number { return getWindowsBuildNumber(); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/terminal/node/terminalRemote.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts similarity index 90% rename from src/vs/workbench/contrib/terminal/node/terminalRemote.ts rename to src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts index 07f2ff1f56..fab36b0428 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalRemote.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts @@ -7,11 +7,11 @@ import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { TERMINAL_ACTION_CATEGORY, ITerminalService, TitleEventSource } from 'vs/workbench/contrib/terminal/common/terminal'; -import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; +import { TERMINAL_ACTION_CATEGORY, TitleEventSource, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal'; import { Action } from 'vs/base/common/actions'; import { URI } from 'vs/base/common/uri'; import { homedir } from 'os'; +import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; export function registerRemoteContributions() { const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); diff --git a/src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts b/src/vs/workbench/contrib/terminal/electron-browser/windowsShellHelper.ts similarity index 95% rename from src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts rename to src/vs/workbench/contrib/terminal/electron-browser/windowsShellHelper.ts index 7f207bed2c..df8fc2942a 100644 --- a/src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/windowsShellHelper.ts @@ -5,10 +5,11 @@ import * as platform from 'vs/base/common/platform'; import { Emitter, Event } from 'vs/base/common/event'; -import { ITerminalInstance, IWindowsShellHelper, TitleEventSource } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IWindowsShellHelper, TitleEventSource } from 'vs/workbench/contrib/terminal/common/terminal'; import { Terminal as XTermTerminal } from 'xterm'; import * as WindowsProcessTreeType from 'windows-process-tree'; import { Disposable } from 'vs/base/common/lifecycle'; +import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; const SHELL_EXECUTABLES = [ 'cmd.exe', diff --git a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts index 6f3f9bae94..28dfd6b42b 100644 --- a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts @@ -4,17 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { Terminal, TerminalCore } from 'xterm'; +import { Terminal } from 'xterm'; import { CommandTrackerAddon } from 'vs/workbench/contrib/terminal/browser/addons/commandTrackerAddon'; import { isWindows } from 'vs/base/common/platform'; - -interface TestTerminalCore extends TerminalCore { - writeBuffer: string[]; - _innerWrite(): void; -} +import { XTermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; interface TestTerminal extends Terminal { - _core: TestTerminalCore; + _core: XTermCore; } function syncWrite(term: TestTerminal, data: string): void { diff --git a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts index 04b2492e4c..7098d2c4d5 100644 --- a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts @@ -35,7 +35,7 @@ class MockTerminalInstanceService implements ITerminalInstanceService { getDefaultShellAndArgs(): Promise<{ shell: string; args: string | string[] | undefined; }> { throw new Error('Method not implemented.'); } - _serviceBrand: any; + _serviceBrand: undefined; getXtermConstructor(): Promise { throw new Error('Method not implemented.'); } diff --git a/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts b/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts index e1f9894ffe..81863721d4 100644 --- a/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts +++ b/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts @@ -5,30 +5,110 @@ import * as assert from 'assert'; import * as platform from 'vs/base/common/platform'; -import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; import { URI as Uri } from 'vs/base/common/uri'; import { IStringDictionary } from 'vs/base/common/collections'; +import { addTerminalEnvironmentKeys, mergeEnvironments, getCwd, getDefaultShell, getLangEnvVariable, shouldSetLangEnvVariable } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; suite('Workbench - TerminalEnvironment', () => { - test('addTerminalEnvironmentKeys', () => { - const env: { [key: string]: any } = { FOO: 'bar' }; - const locale = 'en-au'; - terminalEnvironment.addTerminalEnvironmentKeys(env, '1.2.3', locale, true); - assert.equal(env['TERM_PROGRAM'], 'vscode'); - assert.equal(env['TERM_PROGRAM_VERSION'], '1.2.3'); - assert.equal(env['LANG'], 'en_AU.UTF-8', 'LANG is equal to the requested locale with UTF-8'); + suite('addTerminalEnvironmentKeys', () => { + test('should set expected variables', () => { + const env: { [key: string]: any } = {}; + addTerminalEnvironmentKeys(env, '1.2.3', 'en', 'on'); + assert.equal(env['TERM_PROGRAM'], 'vscode'); + assert.equal(env['TERM_PROGRAM_VERSION'], '1.2.3'); + assert.equal(env['COLORTERM'], 'truecolor'); + assert.equal(env['LANG'], 'en_US.UTF-8'); + }); + test('should use language variant for LANG that is provided in locale', () => { + const env: { [key: string]: any } = {}; + addTerminalEnvironmentKeys(env, '1.2.3', 'en-au', 'on'); + assert.equal(env['LANG'], 'en_AU.UTF-8', 'LANG is equal to the requested locale with UTF-8'); + }); + test('should fallback to en_US when no locale is provided', () => { + const env2: { [key: string]: any } = { FOO: 'bar' }; + addTerminalEnvironmentKeys(env2, '1.2.3', undefined, 'on'); + assert.equal(env2['LANG'], 'en_US.UTF-8', 'LANG is equal to en_US.UTF-8 as fallback.'); // More info on issue #14586 + }); + test('should fallback to en_US when an invalid locale is provided', () => { + const env3 = { LANG: 'replace' }; + addTerminalEnvironmentKeys(env3, '1.2.3', undefined, 'on'); + assert.equal(env3['LANG'], 'en_US.UTF-8', 'LANG is set to the fallback LANG'); + }); + test('should override existing LANG', () => { + const env4 = { LANG: 'en_AU.UTF-8' }; + addTerminalEnvironmentKeys(env4, '1.2.3', undefined, 'on'); + assert.equal(env4['LANG'], 'en_US.UTF-8', 'LANG is equal to the parent environment\'s LANG'); + }); + }); - const env2: { [key: string]: any } = { FOO: 'bar' }; - terminalEnvironment.addTerminalEnvironmentKeys(env2, '1.2.3', undefined, true); - assert.equal(env2['LANG'], 'en_US.UTF-8', 'LANG is equal to en_US.UTF-8 as fallback.'); // More info on issue #14586 + suite('shouldSetLangEnvVariable', () => { + test('auto', () => { + assert.equal(shouldSetLangEnvVariable({}, 'auto'), true); + assert.equal(shouldSetLangEnvVariable({ LANG: 'en-US' }, 'auto'), true); + assert.equal(shouldSetLangEnvVariable({ LANG: 'en-US.UTF-8' }, 'auto'), false); + }); + test('off', () => { + assert.equal(shouldSetLangEnvVariable({}, 'off'), false); + assert.equal(shouldSetLangEnvVariable({ LANG: 'en-US' }, 'off'), false); + assert.equal(shouldSetLangEnvVariable({ LANG: 'en-US.UTF-8' }, 'off'), false); + }); + test('on', () => { + assert.equal(shouldSetLangEnvVariable({}, 'on'), true); + assert.equal(shouldSetLangEnvVariable({ LANG: 'en-US' }, 'on'), true); + assert.equal(shouldSetLangEnvVariable({ LANG: 'en-US.UTF-8' }, 'on'), true); + }); + }); - const env3 = { LANG: 'replace' }; - terminalEnvironment.addTerminalEnvironmentKeys(env3, '1.2.3', undefined, true); - assert.equal(env3['LANG'], 'en_US.UTF-8', 'LANG is set to the fallback LANG'); - - const env4 = { LANG: 'en_US.UTF-8' }; - terminalEnvironment.addTerminalEnvironmentKeys(env3, '1.2.3', undefined, true); - assert.equal(env4['LANG'], 'en_US.UTF-8', 'LANG is equal to the parent environment\'s LANG'); + suite('getLangEnvVariable', () => { + test('should fallback to en_US when no locale is provided', () => { + assert.equal(getLangEnvVariable(undefined), 'en_US.UTF-8'); + assert.equal(getLangEnvVariable(''), 'en_US.UTF-8'); + }); + test('should fallback to default language variants when variant isn\'t provided', () => { + assert.equal(getLangEnvVariable('af'), 'af_ZA.UTF-8'); + assert.equal(getLangEnvVariable('am'), 'am_ET.UTF-8'); + assert.equal(getLangEnvVariable('be'), 'be_BY.UTF-8'); + assert.equal(getLangEnvVariable('bg'), 'bg_BG.UTF-8'); + assert.equal(getLangEnvVariable('ca'), 'ca_ES.UTF-8'); + assert.equal(getLangEnvVariable('cs'), 'cs_CZ.UTF-8'); + assert.equal(getLangEnvVariable('da'), 'da_DK.UTF-8'); + assert.equal(getLangEnvVariable('de'), 'de_DE.UTF-8'); + assert.equal(getLangEnvVariable('el'), 'el_GR.UTF-8'); + assert.equal(getLangEnvVariable('en'), 'en_US.UTF-8'); + assert.equal(getLangEnvVariable('es'), 'es_ES.UTF-8'); + assert.equal(getLangEnvVariable('et'), 'et_EE.UTF-8'); + assert.equal(getLangEnvVariable('eu'), 'eu_ES.UTF-8'); + assert.equal(getLangEnvVariable('fi'), 'fi_FI.UTF-8'); + assert.equal(getLangEnvVariable('fr'), 'fr_FR.UTF-8'); + assert.equal(getLangEnvVariable('he'), 'he_IL.UTF-8'); + assert.equal(getLangEnvVariable('hr'), 'hr_HR.UTF-8'); + assert.equal(getLangEnvVariable('hu'), 'hu_HU.UTF-8'); + assert.equal(getLangEnvVariable('hy'), 'hy_AM.UTF-8'); + assert.equal(getLangEnvVariable('is'), 'is_IS.UTF-8'); + assert.equal(getLangEnvVariable('it'), 'it_IT.UTF-8'); + assert.equal(getLangEnvVariable('ja'), 'ja_JP.UTF-8'); + assert.equal(getLangEnvVariable('kk'), 'kk_KZ.UTF-8'); + assert.equal(getLangEnvVariable('ko'), 'ko_KR.UTF-8'); + assert.equal(getLangEnvVariable('lt'), 'lt_LT.UTF-8'); + assert.equal(getLangEnvVariable('nl'), 'nl_NL.UTF-8'); + assert.equal(getLangEnvVariable('no'), 'no_NO.UTF-8'); + assert.equal(getLangEnvVariable('pl'), 'pl_PL.UTF-8'); + assert.equal(getLangEnvVariable('pt'), 'pt_BR.UTF-8'); + assert.equal(getLangEnvVariable('ro'), 'ro_RO.UTF-8'); + assert.equal(getLangEnvVariable('ru'), 'ru_RU.UTF-8'); + assert.equal(getLangEnvVariable('sk'), 'sk_SK.UTF-8'); + assert.equal(getLangEnvVariable('sl'), 'sl_SI.UTF-8'); + assert.equal(getLangEnvVariable('sr'), 'sr_YU.UTF-8'); + assert.equal(getLangEnvVariable('sv'), 'sv_SE.UTF-8'); + assert.equal(getLangEnvVariable('tr'), 'tr_TR.UTF-8'); + assert.equal(getLangEnvVariable('uk'), 'uk_UA.UTF-8'); + assert.equal(getLangEnvVariable('zh'), 'zh_CN.UTF-8'); + }); + test('should set language variant based on full locale', () => { + assert.equal(getLangEnvVariable('en-AU'), 'en_AU.UTF-8'); + assert.equal(getLangEnvVariable('en-au'), 'en_AU.UTF-8'); + assert.equal(getLangEnvVariable('fa-ke'), 'fa_KE.UTF-8'); + }); }); suite('mergeEnvironments', () => { @@ -39,7 +119,7 @@ suite('Workbench - TerminalEnvironment', () => { const other = { c: 'd' }; - terminalEnvironment.mergeEnvironments(parent, other); + mergeEnvironments(parent, other); assert.deepEqual(parent, { a: 'b', c: 'd' @@ -56,7 +136,7 @@ suite('Workbench - TerminalEnvironment', () => { const other = { A: 'c' }; - terminalEnvironment.mergeEnvironments(parent, other); + mergeEnvironments(parent, other); assert.deepEqual(parent, { a: 'c' }); @@ -70,7 +150,7 @@ suite('Workbench - TerminalEnvironment', () => { const other: IStringDictionary = { a: null }; - terminalEnvironment.mergeEnvironments(parent, other); + mergeEnvironments(parent, other); assert.deepEqual(parent, { c: 'd' }); @@ -87,7 +167,7 @@ suite('Workbench - TerminalEnvironment', () => { const other: IStringDictionary = { A: null }; - terminalEnvironment.mergeEnvironments(parent, other); + mergeEnvironments(parent, other); assert.deepEqual(parent, { c: 'd' }); @@ -101,37 +181,37 @@ suite('Workbench - TerminalEnvironment', () => { } test('should default to userHome for an empty workspace', () => { - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, undefined, undefined), '/userHome/'); + assertPathsMatch(getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, undefined, undefined), '/userHome/'); }); test('should use to the workspace if it exists', () => { - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, Uri.file('/foo'), undefined), '/foo'); + assertPathsMatch(getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, Uri.file('/foo'), undefined), '/foo'); }); test('should use an absolute custom cwd as is', () => { - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, undefined, '/foo'), '/foo'); + assertPathsMatch(getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, undefined, '/foo'), '/foo'); }); test('should normalize a relative custom cwd against the workspace path', () => { - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, Uri.file('/bar'), 'foo'), '/bar/foo'); - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, Uri.file('/bar'), './foo'), '/bar/foo'); - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, Uri.file('/bar'), '../foo'), '/foo'); + assertPathsMatch(getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, Uri.file('/bar'), 'foo'), '/bar/foo'); + assertPathsMatch(getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, Uri.file('/bar'), './foo'), '/bar/foo'); + assertPathsMatch(getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, Uri.file('/bar'), '../foo'), '/foo'); }); test('should fall back for relative a custom cwd that doesn\'t have a workspace', () => { - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, undefined, 'foo'), '/userHome/'); - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, undefined, './foo'), '/userHome/'); - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, undefined, '../foo'), '/userHome/'); + assertPathsMatch(getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, undefined, 'foo'), '/userHome/'); + assertPathsMatch(getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, undefined, './foo'), '/userHome/'); + assertPathsMatch(getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined, undefined, '../foo'), '/userHome/'); }); test('should ignore custom cwd when told to ignore', () => { - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [], ignoreConfigurationCwd: true }, '/userHome/', undefined, undefined, Uri.file('/bar'), '/foo'), '/bar'); + assertPathsMatch(getCwd({ executable: undefined, args: [], ignoreConfigurationCwd: true }, '/userHome/', undefined, undefined, Uri.file('/bar'), '/foo'), '/bar'); }); }); suite('getDefaultShell', () => { test('should change Sysnative to System32 in non-WoW64 systems', () => { - const shell = terminalEnvironment.getDefaultShell(key => { + const shell = getDefaultShell(key => { return ({ 'terminal.integrated.shell.windows': { user: 'C:\\Windows\\Sysnative\\cmd.exe', value: undefined, default: undefined } } as any)[key]; @@ -140,7 +220,7 @@ suite('Workbench - TerminalEnvironment', () => { }); test('should not change Sysnative to System32 in WoW64 systems', () => { - const shell = terminalEnvironment.getDefaultShell(key => { + const shell = getDefaultShell(key => { return ({ 'terminal.integrated.shell.windows': { user: 'C:\\Windows\\Sysnative\\cmd.exe', value: undefined, default: undefined } } as any)[key]; @@ -149,21 +229,21 @@ suite('Workbench - TerminalEnvironment', () => { }); test('should use automationShell when specified', () => { - const shell1 = terminalEnvironment.getDefaultShell(key => { + const shell1 = getDefaultShell(key => { return ({ 'terminal.integrated.shell.windows': { user: 'shell', value: undefined, default: undefined }, 'terminal.integrated.automationShell.windows': { user: undefined, value: undefined, default: undefined } } as any)[key]; }, false, 'DEFAULT', false, 'C:\\Windows', undefined, undefined, {} as any, false, platform.Platform.Windows); assert.equal(shell1, 'shell', 'automationShell was false'); - const shell2 = terminalEnvironment.getDefaultShell(key => { + const shell2 = getDefaultShell(key => { return ({ 'terminal.integrated.shell.windows': { user: 'shell', value: undefined, default: undefined }, 'terminal.integrated.automationShell.windows': { user: undefined, value: undefined, default: undefined } } as any)[key]; }, false, 'DEFAULT', false, 'C:\\Windows', undefined, undefined, {} as any, true, platform.Platform.Windows); assert.equal(shell2, 'shell', 'automationShell was true'); - const shell3 = terminalEnvironment.getDefaultShell(key => { + const shell3 = getDefaultShell(key => { return ({ 'terminal.integrated.shell.windows': { user: 'shell', value: undefined, default: undefined }, 'terminal.integrated.automationShell.windows': { user: 'automationShell', value: undefined, default: undefined } diff --git a/src/vs/workbench/contrib/update/electron-browser/media/code-icon.svg b/src/vs/workbench/contrib/update/browser/media/code-icon.svg similarity index 100% rename from src/vs/workbench/contrib/update/electron-browser/media/code-icon.svg rename to src/vs/workbench/contrib/update/browser/media/code-icon.svg diff --git a/src/vs/workbench/contrib/update/electron-browser/media/markdown.css b/src/vs/workbench/contrib/update/browser/media/markdown.css similarity index 100% rename from src/vs/workbench/contrib/update/electron-browser/media/markdown.css rename to src/vs/workbench/contrib/update/browser/media/markdown.css diff --git a/src/vs/workbench/contrib/update/electron-browser/releaseNotesEditor.ts b/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts similarity index 90% rename from src/vs/workbench/contrib/update/electron-browser/releaseNotesEditor.ts rename to src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts index 32dbf2bca8..417d158934 100644 --- a/src/vs/workbench/contrib/update/electron-browser/releaseNotesEditor.ts +++ b/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts @@ -18,7 +18,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IRequestService, asText } from 'vs/platform/request/common/request'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { addGAParameters } from 'vs/platform/telemetry/node/telemetryNodeUtils'; +import { IProductService } from 'vs/platform/product/common/product'; import { IWebviewEditorService } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { WebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; @@ -45,7 +45,8 @@ export class ReleaseNotesManager { @IEditorService private readonly _editorService: IEditorService, @IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService, @IWebviewEditorService private readonly _webviewEditorService: IWebviewEditorService, - @IExtensionService private readonly _extensionService: IExtensionService + @IExtensionService private readonly _extensionService: IExtensionService, + @IProductService private readonly _productService: IProductService ) { TokenizationRegistry.onDidChange(async () => { if (!this._currentReleaseNotes || !this._lastText) { @@ -161,11 +162,22 @@ export class ReleaseNotesManager { } private onDidClickLink(uri: URI) { - addGAParameters(this._telemetryService, this._environmentService, uri, 'ReleaseNotes') + this.addGAParameters(uri, 'ReleaseNotes') .then(updated => this._openerService.open(updated)) .then(undefined, onUnexpectedError); } + private async addGAParameters(uri: URI, origin: string, experiment = '1'): Promise { + if (this._environmentService.isBuilt && !this._environmentService.isExtensionDevelopment && !this._environmentService.args['disable-telemetry'] && !!this._productService.enableTelemetry) { + if (uri.scheme === 'https' && uri.authority === 'code.visualstudio.com') { + const info = await this._telemetryService.getTelemetryInfo(); + + return uri.with({ query: `${uri.query ? uri.query + '&' : ''}utm_source=VsCode&utm_medium=${encodeURIComponent(origin)}&utm_campaign=${encodeURIComponent(info.instanceId)}&utm_content=${encodeURIComponent(experiment)}` }); + } + } + return uri; + } + private async renderBody(text: string) { const content = await this.renderContent(text); const colorMap = TokenizationRegistry.getColorMap(); diff --git a/src/vs/workbench/contrib/update/browser/update.contribution.ts b/src/vs/workbench/contrib/update/browser/update.contribution.ts new file mode 100644 index 0000000000..c44d7a68d6 --- /dev/null +++ b/src/vs/workbench/contrib/update/browser/update.contribution.ts @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/platform/update/common/update.config.contribution'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution } from 'vs/workbench/contrib/update/browser/update'; +import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; + +const workbench = Registry.as(WorkbenchExtensions.Workbench); + +workbench.registerWorkbenchContribution(ProductContribution, LifecyclePhase.Restored); +workbench.registerWorkbenchContribution(UpdateContribution, LifecyclePhase.Restored); + +// Editor +Registry.as(ActionExtensions.WorkbenchActions) + .registerWorkbenchAction(new SyncActionDescriptor(ShowCurrentReleaseNotesAction, ShowCurrentReleaseNotesAction.ID, ShowCurrentReleaseNotesAction.LABEL), 'Show Release Notes'); diff --git a/src/vs/workbench/contrib/update/browser/update.ts b/src/vs/workbench/contrib/update/browser/update.ts new file mode 100644 index 0000000000..ab5222038a --- /dev/null +++ b/src/vs/workbench/contrib/update/browser/update.ts @@ -0,0 +1,474 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import severity from 'vs/base/common/severity'; +import { Action } from 'vs/base/common/actions'; +import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { URI } from 'vs/base/common/uri'; +import { IActivityService, NumberBadge, IBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { IUpdateService, State as UpdateState, StateType, IUpdate } from 'vs/platform/update/common/update'; +import * as semver from 'semver-umd'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { ReleaseNotesManager } from './releaseNotesEditor'; +import { isWindows } from 'vs/base/common/platform'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +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'; +import { IProductService } from 'vs/platform/product/common/product'; + +const CONTEXT_UPDATE_STATE = new RawContextKey('updateState', StateType.Uninitialized); + +let releaseNotesManager: ReleaseNotesManager | undefined = undefined; + +function showReleaseNotes(instantiationService: IInstantiationService, version: string) { + if (!releaseNotesManager) { + releaseNotesManager = instantiationService.createInstance(ReleaseNotesManager); + } + + return instantiationService.invokeFunction(accessor => releaseNotesManager!.show(accessor, version)); +} + +export class OpenLatestReleaseNotesInBrowserAction extends Action { + + constructor( + @IOpenerService private readonly openerService: IOpenerService, + @IProductService private readonly productService: IProductService + ) { + super('update.openLatestReleaseNotes', nls.localize('releaseNotes', "Release Notes"), undefined, true); + } + + run(): Promise { + if (this.productService.releaseNotesUrl) { + const uri = URI.parse(this.productService.releaseNotesUrl); + return this.openerService.open(uri); + } + return Promise.resolve(false); + } +} + +export abstract class AbstractShowReleaseNotesAction extends Action { + + constructor( + id: string, + label: string, + private version: string, + @IInstantiationService private readonly instantiationService: IInstantiationService + ) { + super(id, label, undefined, true); + } + + run(): Promise { + if (!this.enabled) { + return Promise.resolve(false); + } + + this.enabled = false; + + // return showReleaseNotes(this.instantiationService, this.version) // {{SQL CARBON EDIT}} just open release notes in browser + // .then(undefined, () => { + const action = this.instantiationService.createInstance(OpenLatestReleaseNotesInBrowserAction); + return action.run().then(() => false); + // }); + } +} + +export class ShowReleaseNotesAction extends AbstractShowReleaseNotesAction { + + constructor( + version: string, + @IInstantiationService instantiationService: IInstantiationService + ) { + super('update.showReleaseNotes', nls.localize('releaseNotes', "Release Notes"), version, instantiationService); + } +} + +export class ShowCurrentReleaseNotesAction extends AbstractShowReleaseNotesAction { + + static readonly ID = ShowCurrentReleaseNotesActionId; + static LABEL = nls.localize('showReleaseNotes', "Show Release Notes"); + + constructor( + id = ShowCurrentReleaseNotesAction.ID, + label = ShowCurrentReleaseNotesAction.LABEL, + @IInstantiationService instantiationService: IInstantiationService, + @IProductService productService: IProductService + ) { + super(id, label, productService.version, instantiationService); + } +} + +export class ProductContribution implements IWorkbenchContribution { + + private static readonly KEY = 'releaseNotes/lastVersion'; + + constructor( + @IStorageService storageService: IStorageService, + @IInstantiationService instantiationService: IInstantiationService, + @INotificationService notificationService: INotificationService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IOpenerService openerService: IOpenerService, + @IConfigurationService configurationService: IConfigurationService, + @IWindowService windowService: IWindowService, + @IWindowsService windowsService: IWindowsService, + @IProductService productService: IProductService + ) { + windowsService.getActiveWindowId().then(async windowId => { + if (windowId !== windowService.windowId) { + return; + } + + const lastVersion = storageService.get(ProductContribution.KEY, StorageScope.GLOBAL, ''); + const shouldShowReleaseNotes = configurationService.getValue('update.showReleaseNotes'); + + // was there an update? if so, open release notes + const releaseNotesUrl = productService.releaseNotesUrl; + if (shouldShowReleaseNotes && !environmentService.skipReleaseNotes && releaseNotesUrl && lastVersion && productService.version !== lastVersion) { + showReleaseNotes(instantiationService, productService.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?", productService.nameLong, productService.version), + [{ + label: nls.localize('releaseNotes', "Release Notes"), + run: () => { + const uri = URI.parse(releaseNotesUrl); + openerService.open(uri); + } + }], + { sticky: true } + ); + }); + } + + // should we show the new license? + if (productService.licenseUrl && lastVersion && semver.satisfies(lastVersion, '<1.0.0') && semver.satisfies(productService.version, '>=1.0.0')) { + notificationService.info(nls.localize('licenseChanged', "Our license terms have changed, please click [here]({0}) to go through them.", productService.licenseUrl)); + } + + storageService.store(ProductContribution.KEY, productService.version, StorageScope.GLOBAL); + }); + } +} + +export class UpdateContribution extends Disposable implements IWorkbenchContribution { + + private state: UpdateState; + private readonly badgeDisposable = this._register(new MutableDisposable()); + private updateStateContextKey: IContextKey; + + constructor( + @IStorageService private readonly storageService: IStorageService, + @IInstantiationService private readonly instantiationService: IInstantiationService, + @INotificationService private readonly notificationService: INotificationService, + @IDialogService private readonly dialogService: IDialogService, + @IUpdateService private readonly updateService: IUpdateService, + @IActivityService private readonly activityService: IActivityService, + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IContextKeyService private readonly contextKeyService: IContextKeyService, + @IProductService private readonly productService: IProductService + ) { + super(); + this.state = updateService.state; + this.updateStateContextKey = CONTEXT_UPDATE_STATE.bindTo(this.contextKeyService); + + this._register(updateService.onStateChange(this.onUpdateStateChange, this)); + this.onUpdateStateChange(this.updateService.state); + + /* + The `update/lastKnownVersion` and `update/updateNotificationTime` storage keys are used in + combination to figure out when to show a message to the user that he should update. + + This message should appear if the user has received an update notification but hasn't + updated since 5 days. + */ + + const currentVersion = this.productService.commit; + const lastKnownVersion = this.storageService.get('update/lastKnownVersion', StorageScope.GLOBAL); + + // if current version != stored version, clear both fields + if (currentVersion !== lastKnownVersion) { + this.storageService.remove('update/lastKnownVersion', StorageScope.GLOBAL); + this.storageService.remove('update/updateNotificationTime', StorageScope.GLOBAL); + } + + this.registerGlobalActivityActions(); + } + + private onUpdateStateChange(state: UpdateState): void { + this.updateStateContextKey.set(state.type); + + switch (state.type) { + case StateType.Idle: + if (state.error) { + this.onError(state.error); + } else if (this.state.type === StateType.CheckingForUpdates && this.state.context && this.state.context.windowId === this.environmentService.configuration.windowId) { + this.onUpdateNotAvailable(); + } + break; + + case StateType.AvailableForDownload: + this.onUpdateAvailable(state.update); + break; + + case StateType.Downloaded: + this.onUpdateDownloaded(state.update); + break; + + case StateType.Updating: + this.onUpdateUpdating(state.update); + break; + + case StateType.Ready: + this.onUpdateReady(state.update); + break; + } + + let badge: IBadge | undefined = undefined; + let clazz: string | undefined; + + if (state.type === StateType.AvailableForDownload || state.type === StateType.Downloaded || state.type === StateType.Ready) { + badge = new NumberBadge(1, () => nls.localize('updateIsReady', "New {0} update available.", this.productService.nameLong)); // {{SQL CARBON EDIT}} change to namelong + } else if (state.type === StateType.CheckingForUpdates || state.type === StateType.Downloading || state.type === StateType.Updating) { + badge = new ProgressBadge(() => nls.localize('updateIsReady', "New {0} update available.", this.productService.nameLong)); // {{SQL CARBON EDIT}} change to namelong + clazz = 'progress-badge'; + } + + this.badgeDisposable.clear(); + + if (badge) { + this.badgeDisposable.value = this.activityService.showActivity(GLOBAL_ACTIVITY_ID, badge, clazz); + } + + this.state = state; + } + + private onError(error: string): void { + error = error.replace(/See https:\/\/github\.com\/Squirrel\/Squirrel\.Mac\/issues\/182 for more information/, 'See [this link](https://github.com/Microsoft/vscode/issues/7426#issuecomment-425093469) for more information'); + + this.notificationService.notify({ + severity: Severity.Error, + message: error, + source: nls.localize('update service', "Update Service"), + }); + } + + private onUpdateNotAvailable(): void { + this.dialogService.show( + severity.Info, + nls.localize('noUpdatesAvailable', "There are currently no updates available."), + [nls.localize('ok', "OK")] + ); + } + + // linux + private onUpdateAvailable(update: IUpdate): void { + if (!this.shouldShowNotification()) { + return; + } + + this.notificationService.prompt( + severity.Info, + nls.localize('thereIsUpdateAvailable', "There is an available update."), + [{ + label: nls.localize('download update', "Download Update"), + run: () => this.updateService.downloadUpdate() + }, { + label: nls.localize('later', "Later"), + run: () => { } + }, { + label: nls.localize('releaseNotes', "Release Notes"), + run: () => { + const action = this.instantiationService.createInstance(ShowReleaseNotesAction, update.productVersion); + action.run(); + action.dispose(); + } + }], + { sticky: true } + ); + } + + // windows fast updates (target === system) + private onUpdateDownloaded(update: IUpdate): void { + if (!this.shouldShowNotification()) { + return; + } + + this.notificationService.prompt( + severity.Info, + nls.localize('updateAvailable', "There's an update available: {0} {1}", this.productService.nameLong, update.productVersion), + [{ + label: nls.localize('installUpdate', "Install Update"), + run: () => this.updateService.applyUpdate() + }, { + label: nls.localize('later', "Later"), + run: () => { } + }, { + label: nls.localize('releaseNotes', "Release Notes"), + run: () => { + const action = this.instantiationService.createInstance(ShowReleaseNotesAction, update.productVersion); + action.run(); + action.dispose(); + } + }], + { sticky: true } + ); + } + + // windows fast updates + private onUpdateUpdating(update: IUpdate): void { + if (isWindows && this.productService.target === 'user') { + return; + } + + // windows fast updates (target === system) + this.notificationService.prompt( + severity.Info, + nls.localize('updateInstalling', "{0} {1} is being installed in the background; we'll let you know when it's done.", this.productService.nameLong, update.productVersion), + [], + { + neverShowAgain: { id: 'neverShowAgain:update/win32-fast-updates', isSecondary: true } + } + ); + } + + // windows and mac + private onUpdateReady(update: IUpdate): void { + if (!(isWindows && this.productService.target !== 'user') && !this.shouldShowNotification()) { + return; + } + + const actions = [{ + label: nls.localize('updateNow', "Update Now"), + run: () => this.updateService.quitAndInstall() + }, { + label: nls.localize('later', "Later"), + run: () => { } + }]; + + // TODO@joao check why snap updates send `update` as falsy + if (update.productVersion) { + actions.push({ + label: nls.localize('releaseNotes', "Release Notes"), + run: () => { + const action = this.instantiationService.createInstance(OpenLatestReleaseNotesInBrowserAction); // {{SQL CARBON EDIT}} change action + action.run(); + action.dispose(); + } + }); + } + + // windows user fast updates and mac + this.notificationService.prompt( + severity.Info, + nls.localize('updateAvailableAfterRestart', "Restart {0} to apply the latest update.", this.productService.nameLong), + actions, + { sticky: true } + ); + } + + private shouldShowNotification(): boolean { + const currentVersion = this.productService.commit; + const currentMillis = new Date().getTime(); + const lastKnownVersion = this.storageService.get('update/lastKnownVersion', StorageScope.GLOBAL); + + // if version != stored version, save version and date + if (currentVersion !== lastKnownVersion) { + this.storageService.store('update/lastKnownVersion', currentVersion!, StorageScope.GLOBAL); + this.storageService.store('update/updateNotificationTime', currentMillis, StorageScope.GLOBAL); + } + + const updateNotificationMillis = this.storageService.getNumber('update/updateNotificationTime', StorageScope.GLOBAL, currentMillis); + const diffDays = (currentMillis - updateNotificationMillis) / (1000 * 60 * 60 * 24); + + return diffDays > 5; + } + + private registerGlobalActivityActions(): void { + CommandsRegistry.registerCommand('update.check', () => this.updateService.checkForUpdates({ windowId: this.environmentService.configuration.windowId })); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { + group: '5_update', + command: { + id: 'update.check', + title: nls.localize('checkForUpdates', "Check for Updates...") + }, + when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Idle) + }); + + CommandsRegistry.registerCommand('update.checking', () => { }); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { + group: '5_update', + command: { + id: 'update.checking', + title: nls.localize('checkingForUpdates', "Checking for Updates..."), + precondition: FalseContext + }, + when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.CheckingForUpdates) + }); + + CommandsRegistry.registerCommand('update.downloadNow', () => this.updateService.downloadUpdate()); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { + group: '5_update', + command: { + id: 'update.downloadNow', + title: nls.localize('download update', "Download Update") + }, + when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.AvailableForDownload) + }); + + CommandsRegistry.registerCommand('update.downloading', () => { }); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { + group: '5_update', + command: { + id: 'update.downloading', + title: nls.localize('DownloadingUpdate', "Downloading Update..."), + precondition: FalseContext + }, + when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Downloading) + }); + + CommandsRegistry.registerCommand('update.install', () => this.updateService.applyUpdate()); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { + group: '5_update', + command: { + id: 'update.install', + title: nls.localize('installUpdate...', "Install Update...") + }, + when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Downloaded) + }); + + CommandsRegistry.registerCommand('update.updating', () => { }); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { + group: '5_update', + command: { + id: 'update.updating', + title: nls.localize('installingUpdate', "Installing Update..."), + precondition: FalseContext + }, + when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Updating) + }); + + CommandsRegistry.registerCommand('update.restart', () => this.updateService.quitAndInstall()); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { + group: '5_update', + command: { + id: 'update.restart', + title: nls.localize('restartToUpdate', "Restart to Update") + }, + when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Ready) + }); + } +} diff --git a/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts b/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts index d281b5ca6a..8a22f10e7a 100644 --- a/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts +++ b/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts @@ -3,27 +3,16 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/platform/update/node/update.config.contribution'; import * as platform from 'vs/base/common/platform'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, Win3264BitContribution } from './update'; +import { Win3264BitContribution } from 'vs/workbench/contrib/update/electron-browser/update'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; const workbench = Registry.as(WorkbenchExtensions.Workbench); -workbench.registerWorkbenchContribution(ProductContribution, LifecyclePhase.Restored); - if (platform.isWindows) { if (process.arch === 'ia32') { workbench.registerWorkbenchContribution(Win3264BitContribution, LifecyclePhase.Restored); } } - -workbench.registerWorkbenchContribution(UpdateContribution, LifecyclePhase.Restored); - -// Editor -Registry.as(ActionExtensions.WorkbenchActions) - .registerWorkbenchAction(new SyncActionDescriptor(ShowCurrentReleaseNotesAction, ShowCurrentReleaseNotesAction.ID, ShowCurrentReleaseNotesAction.LABEL), 'Show Release Notes'); diff --git a/src/vs/workbench/contrib/update/electron-browser/update.ts b/src/vs/workbench/contrib/update/electron-browser/update.ts index cb3340c1bb..9a54595b4a 100644 --- a/src/vs/workbench/contrib/update/electron-browser/update.ts +++ b/src/vs/workbench/contrib/update/electron-browser/update.ts @@ -5,165 +5,10 @@ import * as nls from 'vs/nls'; import severity from 'vs/base/common/severity'; -import { Action } from 'vs/base/common/actions'; -import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; -import pkg from 'vs/platform/product/node/package'; import product from 'vs/platform/product/node/product'; -import { URI } from 'vs/base/common/uri'; -import { IActivityService, NumberBadge, IBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity'; -import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IUpdateService, State as UpdateState, StateType, IUpdate } from 'vs/platform/update/common/update'; -import * as semver from 'semver-umd'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { ReleaseNotesManager } from './releaseNotesEditor'; -import { isWindows } from 'vs/base/common/platform'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -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); - -let releaseNotesManager: ReleaseNotesManager | undefined = undefined; - -function showReleaseNotes(instantiationService: IInstantiationService, version: string) { - if (!releaseNotesManager) { - releaseNotesManager = instantiationService.createInstance(ReleaseNotesManager); - } - - return instantiationService.invokeFunction(accessor => releaseNotesManager!.show(accessor, version)); -} - -export class OpenLatestReleaseNotesInBrowserAction extends Action { - - constructor( - @IOpenerService private readonly openerService: IOpenerService - ) { - super('update.openLatestReleaseNotes', nls.localize('releaseNotes', "Release Notes"), undefined, true); - } - - run(): Promise { - if (product.releaseNotesUrl) { - const uri = URI.parse(product.releaseNotesUrl); - return this.openerService.open(uri); - } - return Promise.resolve(false); - } -} - -export abstract class AbstractShowReleaseNotesAction extends Action { - - constructor( - id: string, - label: string, - private version: string, - @IInstantiationService private readonly instantiationService: IInstantiationService - ) { - super(id, label, undefined, true); - } - - run(): Promise { - if (!this.enabled) { - return Promise.resolve(false); - } - - this.enabled = false; - - // {{SQL CARBON EDIT}} - // return showReleaseNotes(this.instantiationService, this.version) - // .then(undefined, () => { - // const action = this.instantiationService.createInstance(OpenLatestReleaseNotesInBrowserAction); - // return action.run().then(() => false); - // }); - const action = this.instantiationService.createInstance(OpenLatestReleaseNotesInBrowserAction); - return action.run().then(() => true); - } -} - -export class ShowReleaseNotesAction extends AbstractShowReleaseNotesAction { - - constructor( - version: string, - @IInstantiationService instantiationService: IInstantiationService - ) { - super('update.showReleaseNotes', nls.localize('releaseNotes', "Release Notes"), version, instantiationService); - } -} - -export class ShowCurrentReleaseNotesAction extends AbstractShowReleaseNotesAction { - - static readonly ID = ShowCurrentReleaseNotesActionId; - static LABEL = nls.localize('showReleaseNotes', "Show Release Notes"); - - constructor( - id = ShowCurrentReleaseNotesAction.ID, - label = ShowCurrentReleaseNotesAction.LABEL, - @IInstantiationService instantiationService: IInstantiationService - ) { - super(id, label, pkg.version, instantiationService); - } -} - -export class ProductContribution implements IWorkbenchContribution { - - private static readonly KEY = 'releaseNotes/lastVersion'; - - constructor( - @IStorageService storageService: IStorageService, - @IInstantiationService instantiationService: IInstantiationService, - @INotificationService notificationService: INotificationService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IOpenerService openerService: IOpenerService, - @IConfigurationService configurationService: IConfigurationService, - @IWindowService windowService: IWindowService, - @IWindowsService windowsService: IWindowsService - ) { - /* windowsService.getActiveWindowId().then(async windowId => { {{SQL CARBON EDIT}} comment out - if (windowId !== windowService.windowId) { - return; - } - - const lastVersion = storageService.get(ProductContribution.KEY, StorageScope.GLOBAL, ''); - const shouldShowReleaseNotes = configurationService.getValue('update.showReleaseNotes'); - - // 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 } - ); - }); - } - - // 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); - });*/ - } -} +import { INotificationService } from 'vs/platform/notification/common/notification'; export class Win3264BitContribution implements IWorkbenchContribution { @@ -171,7 +16,6 @@ export class Win3264BitContribution implements IWorkbenchContribution { private static readonly INSIDER_URL = 'https://github.com/Microsoft/vscode-docs/blob/vnext/release-notes/v1_15.md#windows-64-bit'; constructor( - @IStorageService storageService: IStorageService, @INotificationService notificationService: INotificationService, @IEnvironmentService environmentService: IEnvironmentService ) { @@ -194,314 +38,3 @@ export class Win3264BitContribution implements IWorkbenchContribution { ); } } - -export class UpdateContribution extends Disposable implements IWorkbenchContribution { - - private state: UpdateState; - private readonly badgeDisposable = this._register(new MutableDisposable()); - private updateStateContextKey: IContextKey; - - constructor( - @IStorageService private readonly storageService: IStorageService, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @INotificationService private readonly notificationService: INotificationService, - @IDialogService private readonly dialogService: IDialogService, - @IUpdateService private readonly updateService: IUpdateService, - @IActivityService private readonly activityService: IActivityService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, - @IContextKeyService private readonly contextKeyService: IContextKeyService - ) { - super(); - this.state = updateService.state; - this.updateStateContextKey = CONTEXT_UPDATE_STATE.bindTo(this.contextKeyService); - - this._register(updateService.onStateChange(this.onUpdateStateChange, this)); - this.onUpdateStateChange(this.updateService.state); - - /* - The `update/lastKnownVersion` and `update/updateNotificationTime` storage keys are used in - combination to figure out when to show a message to the user that he should update. - - This message should appear if the user has received an update notification but hasn't - updated since 5 days. - */ - - const currentVersion = product.commit; - const lastKnownVersion = this.storageService.get('update/lastKnownVersion', StorageScope.GLOBAL); - - // if current version != stored version, clear both fields - if (currentVersion !== lastKnownVersion) { - this.storageService.remove('update/lastKnownVersion', StorageScope.GLOBAL); - this.storageService.remove('update/updateNotificationTime', StorageScope.GLOBAL); - } - - this.registerGlobalActivityActions(); - } - - private onUpdateStateChange(state: UpdateState): void { - this.updateStateContextKey.set(state.type); - - switch (state.type) { - case StateType.Idle: - if (state.error) { - this.onError(state.error); - } else if (this.state.type === StateType.CheckingForUpdates && this.state.context && this.state.context.windowId === this.environmentService.configuration.windowId) { - this.onUpdateNotAvailable(); - } - break; - - case StateType.AvailableForDownload: - this.onUpdateAvailable(state.update); - break; - - case StateType.Downloaded: - this.onUpdateDownloaded(state.update); - break; - - case StateType.Updating: - this.onUpdateUpdating(state.update); - break; - - case StateType.Ready: - this.onUpdateReady(state.update); - break; - } - - let badge: IBadge | undefined = undefined; - let clazz: string | undefined; - - if (state.type === StateType.AvailableForDownload || state.type === StateType.Downloaded || state.type === StateType.Ready) { - // {{SQL CARBON EDIT}} - badge = new NumberBadge(1, () => nls.localize('updateIsReady', "New {0} update available.", product.nameLong)); - } else if (state.type === StateType.CheckingForUpdates || state.type === StateType.Downloading || state.type === StateType.Updating) { - // {{SQL CARBON EDIT}} - badge = new ProgressBadge(() => nls.localize('updateIsReady', "New {0} update available.", product.nameLong)); - clazz = 'progress-badge'; - } - - this.badgeDisposable.clear(); - - if (badge) { - this.badgeDisposable.value = this.activityService.showActivity(GLOBAL_ACTIVITY_ID, badge, clazz); - } - - this.state = state; - } - - private onError(error: string): void { - error = error.replace(/See https:\/\/github\.com\/Squirrel\/Squirrel\.Mac\/issues\/182 for more information/, 'See [this link](https://github.com/Microsoft/vscode/issues/7426#issuecomment-425093469) for more information'); - - this.notificationService.notify({ - severity: Severity.Error, - message: error, - source: nls.localize('update service', "Update Service"), - }); - } - - private onUpdateNotAvailable(): void { - this.dialogService.show( - severity.Info, - nls.localize('noUpdatesAvailable', "There are currently no updates available."), - [nls.localize('ok', "OK")] - ); - } - - // linux - private onUpdateAvailable(update: IUpdate): void { - if (!this.shouldShowNotification()) { - return; - } - - this.notificationService.prompt( - severity.Info, - nls.localize('thereIsUpdateAvailable', "There is an available update."), - [{ - label: nls.localize('download update', "Download Update"), - run: () => this.updateService.downloadUpdate() - }, { - label: nls.localize('later', "Later"), - run: () => { } - }, { - label: nls.localize('releaseNotes', "Release Notes"), - run: () => { - const action = this.instantiationService.createInstance(ShowReleaseNotesAction, update.productVersion); - action.run(); - action.dispose(); - } - }], - { sticky: true } - ); - } - - // windows fast updates (target === system) - private onUpdateDownloaded(update: IUpdate): void { - if (!this.shouldShowNotification()) { - return; - } - - this.notificationService.prompt( - severity.Info, - nls.localize('updateAvailable', "There's an update available: {0} {1}", product.nameLong, update.productVersion), - [{ - label: nls.localize('installUpdate', "Install Update"), - run: () => this.updateService.applyUpdate() - }, { - label: nls.localize('later', "Later"), - run: () => { } - }, { - label: nls.localize('releaseNotes', "Release Notes"), - run: () => { - const action = this.instantiationService.createInstance(ShowReleaseNotesAction, update.productVersion); - action.run(); - action.dispose(); - } - }], - { sticky: true } - ); - } - - // windows fast updates - private onUpdateUpdating(update: IUpdate): void { - if (isWindows && product.target === 'user') { - return; - } - - // windows fast updates (target === system) - this.notificationService.prompt( - severity.Info, - nls.localize('updateInstalling', "{0} {1} is being installed in the background; we'll let you know when it's done.", product.nameLong, update.productVersion), - [], - { - neverShowAgain: { id: 'neverShowAgain:update/win32-fast-updates', isSecondary: true } - } - ); - } - - // windows and mac - private onUpdateReady(update: IUpdate): void { - if (!(isWindows && product.target !== 'user') && !this.shouldShowNotification()) { - return; - } - - const actions = [{ - label: nls.localize('updateNow', "Update Now"), - run: () => this.updateService.quitAndInstall() - }, { - label: nls.localize('later', "Later"), - run: () => { } - }]; - - // TODO@joao check why snap updates send `update` as falsy - if (update.productVersion) { - actions.push({ - label: nls.localize('releaseNotes', "Release Notes"), - run: () => { - // {{SQL CARBON EDIT}} - const action = this.instantiationService.createInstance(OpenLatestReleaseNotesInBrowserAction); - action.run(); - action.dispose(); - } - }); - } - - // windows user fast updates and mac - this.notificationService.prompt( - severity.Info, - nls.localize('updateAvailableAfterRestart', "Restart {0} to apply the latest update.", product.nameLong), - actions, - { sticky: true } - ); - } - - private shouldShowNotification(): boolean { - const currentVersion = product.commit; - const currentMillis = new Date().getTime(); - const lastKnownVersion = this.storageService.get('update/lastKnownVersion', StorageScope.GLOBAL); - - // if version != stored version, save version and date - if (currentVersion !== lastKnownVersion) { - this.storageService.store('update/lastKnownVersion', currentVersion!, StorageScope.GLOBAL); - this.storageService.store('update/updateNotificationTime', currentMillis, StorageScope.GLOBAL); - } - - const updateNotificationMillis = this.storageService.getNumber('update/updateNotificationTime', StorageScope.GLOBAL, currentMillis); - const diffDays = (currentMillis - updateNotificationMillis) / (1000 * 60 * 60 * 24); - - return diffDays > 5; - } - - private registerGlobalActivityActions(): void { - CommandsRegistry.registerCommand('update.check', () => this.updateService.checkForUpdates({ windowId: this.environmentService.configuration.windowId })); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '5_update', - command: { - id: 'update.check', - title: nls.localize('checkForUpdates', "Check for Updates...") - }, - when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Idle) - }); - - CommandsRegistry.registerCommand('update.checking', () => { }); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '5_update', - command: { - id: 'update.checking', - title: nls.localize('checkingForUpdates', "Checking for Updates..."), - precondition: FalseContext - }, - when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.CheckingForUpdates) - }); - - CommandsRegistry.registerCommand('update.downloadNow', () => this.updateService.downloadUpdate()); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '5_update', - command: { - id: 'update.downloadNow', - title: nls.localize('download update', "Download Update") - }, - when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.AvailableForDownload) - }); - - CommandsRegistry.registerCommand('update.downloading', () => { }); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '5_update', - command: { - id: 'update.downloading', - title: nls.localize('DownloadingUpdate', "Downloading Update..."), - precondition: FalseContext - }, - when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Downloading) - }); - - CommandsRegistry.registerCommand('update.install', () => this.updateService.applyUpdate()); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '5_update', - command: { - id: 'update.install', - title: nls.localize('installUpdate...', "Install Update...") - }, - when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Downloaded) - }); - - CommandsRegistry.registerCommand('update.updating', () => { }); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '5_update', - command: { - id: 'update.updating', - title: nls.localize('installingUpdate', "Installing Update..."), - precondition: FalseContext - }, - when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Updating) - }); - - CommandsRegistry.registerCommand('update.restart', () => this.updateService.quitAndInstall()); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '5_update', - command: { - id: 'update.restart', - title: nls.localize('restartToUpdate', "Restart to Update") - }, - when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Ready) - }); - } -} diff --git a/src/vs/workbench/contrib/url/common/url.contribution.ts b/src/vs/workbench/contrib/url/common/url.contribution.ts index 056a231b42..3e0466dba1 100644 --- a/src/vs/workbench/contrib/url/common/url.contribution.ts +++ b/src/vs/workbench/contrib/url/common/url.contribution.ts @@ -14,7 +14,11 @@ import { Action } from 'vs/base/common/actions'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { + IWorkbenchContribution, + IWorkbenchContributionsRegistry, + Extensions as WorkbenchExtensions +} from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IProductService } from 'vs/platform/product/common/product'; @@ -50,29 +54,20 @@ Registry.as(ActionExtensions.WorkbenchActions).registe localize('developer', 'Developer') ); -const DEAFULT_TRUSTED_DOMAINS = [ - 'https://code.visualstudio.com', - 'https://go.microsoft.com', - 'https://github.com', - 'https://marketplace.visualstudio.com', - 'https://vscode-auth.github.com' -]; - const configureTrustedDomainsHandler = async ( quickInputService: IQuickInputService, storageService: IStorageService, + linkProtectionTrustedDomains: string[], domainToConfigure?: string ) => { - let trustedDomains: string[] = DEAFULT_TRUSTED_DOMAINS; - try { - const trustedDomainsSrc = storageService.get('http.trustedDomains', StorageScope.GLOBAL); + const trustedDomainsSrc = storageService.get('http.linkProtectionTrustedDomains', StorageScope.GLOBAL); if (trustedDomainsSrc) { - trustedDomains = JSON.parse(trustedDomainsSrc); + linkProtectionTrustedDomains = JSON.parse(trustedDomainsSrc); } } catch (err) { } - const domainQuickPickItems: IQuickPickItem[] = trustedDomains + const domainQuickPickItems: IQuickPickItem[] = linkProtectionTrustedDomains .filter(d => d !== '*') .map(d => { return { @@ -88,12 +83,12 @@ const configureTrustedDomainsHandler = async ( type: 'item', label: localize('openAllLinksWithoutPrompt', 'Open all links without prompt'), id: '*', - picked: trustedDomains.indexOf('*') !== -1 + picked: linkProtectionTrustedDomains.indexOf('*') !== -1 } ]; let domainToConfigureItem: IQuickPickItem | undefined = undefined; - if (domainToConfigure && trustedDomains.indexOf(domainToConfigure) === -1) { + if (domainToConfigure && linkProtectionTrustedDomains.indexOf(domainToConfigure) === -1) { domainToConfigureItem = { type: 'item', label: domainToConfigure, @@ -116,7 +111,7 @@ const configureTrustedDomainsHandler = async ( if (pickedResult) { const pickedDomains: string[] = pickedResult.map(r => r.id!); - storageService.store('http.trustedDomains', JSON.stringify(pickedDomains), StorageScope.GLOBAL); + storageService.store('http.linkProtectionTrustedDomains', JSON.stringify(pickedDomains), StorageScope.GLOBAL); return pickedDomains; } @@ -125,16 +120,21 @@ const configureTrustedDomainsHandler = async ( }; const configureTrustedDomainCommand = { - id: 'workbench.action.configureTrustedDomains', + id: 'workbench.action.configureLinkProtectionTrustedDomains', description: { - description: localize('configureTrustedDomains', 'Configure Trusted Domains'), + description: localize('configureLinkProtectionTrustedDomains', 'Configure Trusted Domains for Link Protection'), args: [{ name: 'domainToConfigure', schema: { type: 'string' } }] }, handler: (accessor: ServicesAccessor, domainToConfigure?: string) => { const quickInputService = accessor.get(IQuickInputService); const storageService = accessor.get(IStorageService); + const productService = accessor.get(IProductService); - return configureTrustedDomainsHandler(quickInputService, storageService, domainToConfigure); + const trustedDomains = productService.linkProtectionTrustedDomains + ? [...productService.linkProtectionTrustedDomains] + : []; + + return configureTrustedDomainsHandler(quickInputService, storageService, trustedDomains, domainToConfigure); } }; @@ -164,9 +164,12 @@ class OpenerValidatorContributions implements IWorkbenchContribution { return true; } - let trustedDomains: string[] = DEAFULT_TRUSTED_DOMAINS; + let trustedDomains: string[] = this._productService.linkProtectionTrustedDomains + ? [...this._productService.linkProtectionTrustedDomains] + : []; + try { - const trustedDomainsSrc = this._storageService.get('http.trustedDomains', StorageScope.GLOBAL); + const trustedDomainsSrc = this._storageService.get('http.linkProtectionTrustedDomains', StorageScope.GLOBAL); if (trustedDomainsSrc) { trustedDomains = JSON.parse(trustedDomainsSrc); } @@ -174,10 +177,10 @@ class OpenerValidatorContributions implements IWorkbenchContribution { const domainToOpen = `${scheme}://${authority}`; - if (isDomainTrusted(domainToOpen, trustedDomains)) { + if (isURLDomainTrusted(resource, trustedDomains)) { return true; } else { - const choice = await this._dialogService.show( + const { choice } = await this._dialogService.show( Severity.Info, localize( 'openExternalLinkAt', @@ -201,7 +204,12 @@ class OpenerValidatorContributions implements IWorkbenchContribution { } // Configure Trusted Domains else if (choice === 2) { - const pickedDomains = await configureTrustedDomainsHandler(this._quickInputService, this._storageService, domainToOpen); + const pickedDomains = await configureTrustedDomainsHandler( + this._quickInputService, + this._storageService, + trustedDomains, + domainToOpen + ); if (pickedDomains.indexOf(domainToOpen) !== -1) { return true; } @@ -218,11 +226,28 @@ Registry.as(WorkbenchExtensions.Workbench).regi LifecyclePhase.Restored ); +const rLocalhost = /^localhost(:\d+)?$/i; +const r127 = /^127.0.0.1(:\d+)?$/; + +function isLocalhostAuthority(authority: string) { + return rLocalhost.test(authority) || r127.test(authority); +} + /** * Check whether a domain like https://www.microsoft.com matches * the list of trusted domains. + * + * - Schemes must match + * - There's no subdomain matching. For example https://microsoft.com doesn't match https://www.microsoft.com + * - Star matches all. For example https://*.microsoft.com matches https://www.microsoft.com */ -function isDomainTrusted(domain: string, trustedDomains: string[]) { +export function isURLDomainTrusted(url: URI, trustedDomains: string[]) { + if (isLocalhostAuthority(url.authority)) { + return true; + } + + const domain = `${url.scheme}://${url.authority}`; + for (let i = 0; i < trustedDomains.length; i++) { if (trustedDomains[i] === '*') { return true; @@ -231,6 +256,24 @@ function isDomainTrusted(domain: string, trustedDomains: string[]) { if (trustedDomains[i] === domain) { return true; } + + if (trustedDomains[i].indexOf('*') !== -1) { + const parsedTrustedDomain = URI.parse(trustedDomains[i]); + if (url.scheme === parsedTrustedDomain.scheme) { + const authoritySegments = url.authority.split('.'); + const trustedDomainAuthoritySegments = parsedTrustedDomain.authority.split('.'); + + if (authoritySegments.length === trustedDomainAuthoritySegments.length) { + if ( + authoritySegments.every( + (val, i) => trustedDomainAuthoritySegments[i] === '*' || val === trustedDomainAuthoritySegments[i] + ) + ) { + return true; + } + } + } + } } return false; diff --git a/src/vs/workbench/contrib/watermark/browser/watermark.ts b/src/vs/workbench/contrib/watermark/browser/watermark.ts index 311315b904..60f19e5bf9 100644 --- a/src/vs/workbench/contrib/watermark/browser/watermark.ts +++ b/src/vs/workbench/contrib/watermark/browser/watermark.ts @@ -22,12 +22,12 @@ import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/bro import { StartAction } from 'vs/workbench/contrib/debug/browser/debugActions'; import { FindInFilesActionId } from 'vs/workbench/contrib/search/common/constants'; import { QUICKOPEN_ACTION_ID } from 'vs/workbench/browser/parts/quickopen/quickopen'; -import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; import * as dom from 'vs/base/browser/dom'; import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IDimension } from 'vs/platform/layout/browser/layoutService'; +import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal'; // {{SQL CARBON EDIT}} import { NewNotebookAction } from 'sql/workbench/parts/notebook/browser/notebookActions'; diff --git a/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts b/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts index 6910912e15..4ff6dea781 100644 --- a/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts +++ b/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts @@ -3,12 +3,13 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { memoize } from 'vs/base/common/decorators'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IWebviewService, Webview, WebviewContentOptions, WebviewEditorOverlay, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; -import { memoize } from 'vs/base/common/decorators'; /** * Webview editor overlay that creates and destroys the underlying webview as needed. @@ -76,6 +77,7 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewEd webview.onDidFocus(() => { this._onDidFocus.fire(); }, undefined, this._webviewEvents); webview.onDidClickLink(x => { this._onDidClickLink.fire(x); }, undefined, this._webviewEvents); webview.onMessage(x => { this._onMessage.fire(x); }, undefined, this._webviewEvents); + webview.onMissingCsp(x => { this._onMissingCsp.fire(x); }, undefined, this._webviewEvents); webview.onDidScroll(x => { this._initialScrollProgress = x.scrollYPercentage; @@ -132,6 +134,9 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewEd private readonly _onMessage = this._register(new Emitter()); public readonly onMessage: Event = this._onMessage.event; + private readonly _onMissingCsp = this._register(new Emitter()); + public readonly onMissingCsp: Event = this._onMissingCsp.event; + sendMessage(data: any): void { if (this._webview.value) { this._webview.value.sendMessage(data); diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js index 2dc6eae30f..6674eb77fd 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/main.js +++ b/src/vs/workbench/contrib/webview/browser/pre/main.js @@ -188,11 +188,6 @@ return; } - // Prevent middle clicks opening a broken link in the browser - if (event.button == 1) { - event.preventDefault(); - } - let baseElement = event.view.document.getElementsByTagName('base')[0]; /** @type {any} */ let node = event.target; @@ -215,6 +210,27 @@ } }; + /** + * @param {MouseEvent} event + */ + const handleAuxClick = (event) => { + // Prevent middle clicks opening a broken link in the browser + if (!event.view || !event.view.document) { + return; + } + + if (event.button === 1) { + let node = /** @type {any} */ (event.target); + while (node) { + if (node.tagName && node.tagName.toLowerCase() === 'a' && node.href) { + event.preventDefault(); + break; + } + node = node.parentNode; + } + } + }; + /** * @param {KeyboardEvent} e */ @@ -459,7 +475,8 @@ }); // Bubble out link clicks - newFrame.contentWindow.addEventListener('mousedown', handleInnerClick); + newFrame.contentWindow.addEventListener('click', handleInnerClick); + newFrame.contentWindow.addEventListener('auxclick', handleAuxClick); if (host.onIframeLoaded) { host.onIframeLoaded(newFrame); diff --git a/src/vs/workbench/contrib/webview/browser/webview.ts b/src/vs/workbench/contrib/webview/browser/webview.ts index a403e797de..9c4e2fc873 100644 --- a/src/vs/workbench/contrib/webview/browser/webview.ts +++ b/src/vs/workbench/contrib/webview/browser/webview.ts @@ -24,7 +24,7 @@ export const IWebviewService = createDecorator('webviewService' * Handles the creation of webview elements. */ export interface IWebviewService { - _serviceBrand: any; + _serviceBrand: undefined; createWebview( id: string, @@ -70,6 +70,7 @@ export interface Webview extends IDisposable { readonly onDidScroll: Event<{ scrollYPercentage: number }>; readonly onDidUpdateState: Event; readonly onMessage: Event; + readonly onMissingCsp: Event; sendMessage(data: any): void; update( diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditor.ts b/src/vs/workbench/contrib/webview/browser/webviewEditor.ts index 7f5d8a0db5..576dc0dc4e 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditor.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditor.ts @@ -13,7 +13,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { EditorOptions } from 'vs/workbench/common/editor'; +import { EditorOptions, EditorInput } from 'vs/workbench/common/editor'; import { WebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, Webview, WebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/webview'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -21,7 +21,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic export class WebviewEditor extends BaseEditor { - public static readonly ID = 'WebviewEditor'; + public static ID = 'WebviewEditor'; private readonly _scopedContextKeyService = this._register(new MutableDisposable()); private _findWidgetVisible: IContextKey; @@ -88,9 +88,9 @@ export class WebviewEditor extends BaseEditor { this.withWebview(webview => webview.reload()); } - public layout(_dimension: DOM.Dimension): void { + public layout(dimension: DOM.Dimension): void { if (this.input && this.input instanceof WebviewEditorInput) { - this.synchronizeWebviewContainerDimensions(this.input.webview); + this.synchronizeWebviewContainerDimensions(this.input.webview, dimension); this.input.webview.layout(); } } @@ -114,7 +114,7 @@ export class WebviewEditor extends BaseEditor { } } - protected setEditorVisible(visible: boolean, group: IEditorGroup): void { + protected setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void { const webview = this.input && (this.input as WebviewEditorInput).webview; if (webview) { if (visible) { @@ -136,7 +136,11 @@ export class WebviewEditor extends BaseEditor { super.clearInput(); } - public async setInput(input: WebviewEditorInput, options: EditorOptions, token: CancellationToken): Promise { + public async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { + if (input.matches(this.input)) { + return; + } + if (this.input && this.input instanceof WebviewEditorInput) { this.input.webview.release(this); } @@ -147,11 +151,13 @@ export class WebviewEditor extends BaseEditor { return; } - if (this.group) { - input.updateGroup(this.group.id); - } + if (input instanceof WebviewEditorInput) { + if (this.group) { + input.updateGroup(this.group.id); + } - this.claimWebview(input); + this.claimWebview(input); + } } private claimWebview(input: WebviewEditorInput): void { @@ -170,17 +176,16 @@ export class WebviewEditor extends BaseEditor { this.trackFocus(input.webview); } - private synchronizeWebviewContainerDimensions(webview: WebviewEditorOverlay) { + private synchronizeWebviewContainerDimensions(webview: WebviewEditorOverlay, dimension?: DOM.Dimension) { const webviewContainer = webview.container; if (webviewContainer && webviewContainer.parentElement && this._editorFrame) { const frameRect = this._editorFrame.getBoundingClientRect(); const containerRect = webviewContainer.parentElement.getBoundingClientRect(); - webviewContainer.style.position = 'absolute'; webviewContainer.style.top = `${frameRect.top - containerRect.top}px`; webviewContainer.style.left = `${frameRect.left - containerRect.left}px`; - webviewContainer.style.width = `${frameRect.width}px`; - webviewContainer.style.height = `${frameRect.height}px`; + webviewContainer.style.width = `${dimension ? dimension.width : frameRect.width}px`; + webviewContainer.style.height = `${dimension ? dimension.height : frameRect.height}px`; } } diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts index 3d12b9ed27..973de6d983 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts @@ -7,10 +7,12 @@ import { memoize } from 'vs/base/common/decorators'; import { URI } from 'vs/base/common/uri'; import { IEditorModel } from 'vs/platform/editor/common/editor'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import { EditorInput, EditorModel, GroupIdentifier, IEditorInput } from 'vs/workbench/common/editor'; +import { EditorInput, EditorModel, GroupIdentifier, IEditorInput, Verbosity } from 'vs/workbench/common/editor'; import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/webview'; import { UnownedDisposable as Unowned } from 'vs/base/common/lifecycle'; +const WebviewPanelResourceScheme = 'webview-panel'; + class WebviewIconsManager { private readonly _icons = new Map(); @@ -52,7 +54,7 @@ class WebviewIconsManager { export class WebviewEditorInput extends EditorInput { - public static readonly typeId = 'workbench.editors.webviewInput'; + public static typeId = 'workbench.editors.webviewInput'; private static readonly iconsManager = new WebviewIconsManager(); @@ -69,7 +71,7 @@ export class WebviewEditorInput extends EditorInput { readonly location: URI; readonly id: ExtensionIdentifier; }, - webview: Unowned, + webview: Unowned ) { super(); @@ -85,7 +87,7 @@ export class WebviewEditorInput extends EditorInput { public getResource(): URI { return URI.from({ - scheme: 'webview-panel', + scheme: WebviewPanelResourceScheme, path: `webview-panel/webview-${this.id}` }); } @@ -94,7 +96,7 @@ export class WebviewEditorInput extends EditorInput { return this._name; } - public getTitle() { + public getTitle(_verbosity?: Verbosity) { return this.getName(); } @@ -153,7 +155,7 @@ export class RevivedWebviewEditorInput extends WebviewEditorInput { readonly id: ExtensionIdentifier }, private readonly reviver: (input: WebviewEditorInput) => Promise, - webview: Unowned, + webview: Unowned ) { super(id, viewType, name, extension, webview); } diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts index 995a9385b3..903ea0589c 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts @@ -3,13 +3,13 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { URI, UriComponents } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorInputFactory } from 'vs/workbench/common/editor'; import { WebviewEditorInput } from './webviewEditorInput'; import { IWebviewEditorService, WebviewInputOptions } from './webviewEditorService'; -import { URI, UriComponents } from 'vs/base/common/uri'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import { generateUuid } from 'vs/base/common/uuid'; interface SerializedIconPath { light: string | UriComponents; @@ -35,24 +35,12 @@ export class WebviewEditorInputFactory implements IEditorInputFactory { @IWebviewEditorService private readonly _webviewService: IWebviewEditorService ) { } - public serialize( - input: WebviewEditorInput - ): string | undefined { + public serialize(input: WebviewEditorInput): string | undefined { if (!this._webviewService.shouldPersist(input)) { return undefined; } - const data: SerializedWebview = { - viewType: input.viewType, - title: input.getName(), - options: { ...input.webview.options, ...input.webview.contentOptions }, - extensionLocation: input.extension ? input.extension.location : undefined, - extensionId: input.extension && input.extension.id ? input.extension.id.value : undefined, - state: input.webview.state, - iconPath: input.iconPath ? { light: input.iconPath.light, dark: input.iconPath.dark, } : undefined, - group: input.group - }; - + const data = this.toJson(input); try { return JSON.stringify(data); } catch { @@ -64,17 +52,36 @@ export class WebviewEditorInputFactory implements IEditorInputFactory { _instantiationService: IInstantiationService, serializedEditorInput: string ): WebviewEditorInput { - const data: SerializedWebview = JSON.parse(serializedEditorInput); - const extensionLocation = reviveUri(data.extensionLocation); - const extensionId = data.extensionId ? new ExtensionIdentifier(data.extensionId) : undefined; - const iconPath = reviveIconPath(data.iconPath); - const state = reviveState(data.state); - - return this._webviewService.reviveWebview(generateUuid(), data.viewType, data.title, iconPath, state, data.options, extensionLocation ? { - location: extensionLocation, - id: extensionId + const data = this.fromJson(serializedEditorInput); + return this._webviewService.reviveWebview(generateUuid(), data.viewType, data.title, data.iconPath, data.state, data.options, data.extensionLocation ? { + location: data.extensionLocation, + id: data.extensionId } : undefined, data.group); } + + protected fromJson(serializedEditorInput: string) { + const data: SerializedWebview = JSON.parse(serializedEditorInput); + return { + ...data, + extensionLocation: reviveUri(data.extensionLocation), + extensionId: data.extensionId ? new ExtensionIdentifier(data.extensionId) : undefined, + iconPath: reviveIconPath(data.iconPath), + state: reviveState(data.state), + }; + } + + protected toJson(input: WebviewEditorInput): SerializedWebview { + return { + viewType: input.viewType, + title: input.getName(), + options: { ...input.webview.options, ...input.webview.contentOptions }, + extensionLocation: input.extension ? input.extension.location : undefined, + extensionId: input.extension && input.extension.id ? input.extension.id.value : undefined, + state: input.webview.state, + iconPath: input.iconPath ? { light: input.iconPath.light, dark: input.iconPath.dark, } : undefined, + group: input.group + }; + } } function reviveIconPath(data: SerializedIconPath | undefined) { diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts index 0d2032646b..f973e6d867 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts @@ -16,6 +16,7 @@ import { ACTIVE_GROUP_TYPE, IEditorService, SIDE_GROUP_TYPE } from 'vs/workbench import { RevivedWebviewEditorInput, WebviewEditorInput } from './webviewEditorInput'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { EditorActivation } from 'vs/platform/editor/common/editor'; export const IWebviewEditorService = createDecorator('webviewEditorService'); @@ -25,7 +26,7 @@ export interface ICreateWebViewShowOptions { } export interface IWebviewEditorService { - _serviceBrand: any; + _serviceBrand: undefined; createWebview( id: string, @@ -59,22 +60,26 @@ export interface IWebviewEditorService { preserveFocus: boolean ): void; - registerReviver( - reviver: WebviewReviver + registerResolver( + reviver: WebviewResolve ): IDisposable; shouldPersist( input: WebviewEditorInput ): boolean; + + resolveWebview( + webview: WebviewEditorInput, + ): Promise; } -export interface WebviewReviver { - canRevive( - webview: WebviewEditorInput +export interface WebviewResolve { + canResolve( + webview: WebviewEditorInput, ): boolean; - reviveWebview( - webview: WebviewEditorInput + resolveWebview( + webview: WebviewEditorInput, ): Promise; } @@ -94,11 +99,11 @@ export function areWebviewInputOptionsEqual(a: WebviewInputOptions, b: WebviewIn && (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 { +function canRevive(reviver: WebviewResolve, webview: WebviewEditorInput): boolean { if (webview.isDisposed()) { return false; } - return reviver.canRevive(webview); + return reviver.canResolve(webview); } class RevivalPool { @@ -108,20 +113,20 @@ class RevivalPool { this._awaitingRevival.push({ input, resolve }); } - public reviveFor(reviver: WebviewReviver) { + public reviveFor(reviver: WebviewResolve) { const toRevive = this._awaitingRevival.filter(({ input }) => canRevive(reviver, input)); this._awaitingRevival = this._awaitingRevival.filter(({ input }) => !canRevive(reviver, input)); for (const { input, resolve } of toRevive) { - reviver.reviveWebview(input).then(resolve); + reviver.resolveWebview(input).then(resolve); } } } export class WebviewEditorService implements IWebviewEditorService { - _serviceBrand: any; + _serviceBrand: undefined; - private readonly _revivers = new Set(); + private readonly _revivers = new Set(); private readonly _revivalPool = new RevivalPool(); constructor( @@ -145,8 +150,14 @@ export class WebviewEditorService implements IWebviewEditorService { ): WebviewEditorInput { const webview = this.createWebiew(id, extension, options); - const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, id, viewType, title, extension, new UnownedDisposable(webview)); - this._editorService.openEditor(webviewInput, { pinned: true, preserveFocus: showOptions.preserveFocus }, showOptions.group); + const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, id, viewType, title, extension, new UnownedDisposable(webview), undefined); + this._editorService.openEditor(webviewInput, { + pinned: true, + preserveFocus: showOptions.preserveFocus, + // preserve pre 1.38 behaviour to not make group active when preserveFocus: true + // but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633 + activation: showOptions.preserveFocus ? EditorActivation.RESTORE : undefined + }, showOptions.group); return webviewInput; } @@ -156,7 +167,12 @@ export class WebviewEditorService implements IWebviewEditorService { preserveFocus: boolean ): void { if (webview.group === group.id) { - this._editorService.openEditor(webview, { preserveFocus }, webview.group); + this._editorService.openEditor(webview, { + preserveFocus, + // preserve pre 1.38 behaviour to not make group active when preserveFocus: true + // but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633 + activation: preserveFocus ? EditorActivation.RESTORE : undefined + }, webview.group); } else { const groupView = this._editorGroupService.getGroup(webview.group!); if (groupView) { @@ -202,8 +218,8 @@ export class WebviewEditorService implements IWebviewEditorService { return webviewInput; } - public registerReviver( - reviver: WebviewReviver + public registerResolver( + reviver: WebviewResolve ): IDisposable { this._revivers.add(reviver); this._revivalPool.reviveFor(reviver); @@ -235,22 +251,31 @@ export class WebviewEditorService implements IWebviewEditorService { ): Promise { for (const reviver of values(this._revivers)) { if (canRevive(reviver, webview)) { - await reviver.reviveWebview(webview); + await reviver.resolveWebview(webview); return true; } } return false; } + public async resolveWebview( + webview: WebviewEditorInput, + ): Promise { + const didRevive = await this.tryRevive(webview); + if (!didRevive) { + this._revivalPool.add(webview, () => { }); + } + } + private createWebiew(id: string, extension: { location: URI; id: ExtensionIdentifier; } | undefined, options: WebviewInputOptions) { return this._webviewService.createWebviewEditorOverlay(id, { extension: extension, enableFindWidget: options.enableFindWidget, retainContextWhenHidden: options.retainContextWhenHidden }, { - ...options, - localResourceRoots: options.localResourceRoots || this.getDefaultLocalResourceRoots(extension), - }); + ...options, + localResourceRoots: options.localResourceRoots || this.getDefaultLocalResourceRoots(extension), + }); } private getDefaultLocalResourceRoots(extension: undefined | { diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index 34b356c61b..ac92123a9a 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -3,20 +3,23 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { addClass, addDisposableListener } from 'vs/base/browser/dom'; import { Emitter } from 'vs/base/common/event'; -import { URI } from 'vs/base/common/uri'; -import { Webview, WebviewContentOptions, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; -import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IFileService } from 'vs/platform/files/common/files'; import { Disposable } from 'vs/base/common/lifecycle'; -import { areWebviewInputOptionsEqual } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; -import { addDisposableListener, addClass } from 'vs/base/browser/dom'; -import { getWebviewThemeData } from 'vs/workbench/contrib/webview/common/themeing'; +import { URI } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { loadLocalResource } from 'vs/workbench/contrib/webview/common/resourceLoader'; -import { WebviewPortMappingManager } from 'vs/workbench/contrib/webview/common/portMapping'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { IFileService } from 'vs/platform/files/common/files'; +import product from 'vs/platform/product/browser/product'; import { ITunnelService } from 'vs/platform/remote/common/tunnel'; +import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; +import { Webview, WebviewContentOptions, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; +import { areWebviewInputOptionsEqual } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; +import { WebviewPortMappingManager } from 'vs/workbench/contrib/webview/common/portMapping'; +import { loadLocalResource } from 'vs/workbench/contrib/webview/common/resourceLoader'; +import { getWebviewThemeData } from 'vs/workbench/contrib/webview/common/themeing'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { isWeb } from 'vs/base/common/platform'; interface WebviewContent { readonly html: string; @@ -45,9 +48,7 @@ export class IFrameWebview extends Disposable implements Webview { @IConfigurationService private readonly _configurationService: IConfigurationService, ) { super(); - const useExternalEndpoint = this._configurationService.getValue('webview.experimental.useExternalEndpoint'); - - if (!useExternalEndpoint && (!environmentService.options || typeof environmentService.options.webviewEndpoint !== 'string')) { + if (!this.useExternalEndpoint && (!environmentService.options || typeof environmentService.options.webviewEndpoint !== 'string')) { throw new Error('To use iframe based webviews, you must configure `environmentService.webviewEndpoint`'); } @@ -144,8 +145,7 @@ export class IFrameWebview extends Disposable implements Webview { } private get endpoint(): string { - const useExternalEndpoint = this._configurationService.getValue('webview.experimental.useExternalEndpoint'); - const baseEndpoint = useExternalEndpoint ? 'https://{{uuid}}.vscode-webview-test.com/8fa811108f0f0524c473020ef57b6620f6c201e1' : this.environmentService.options!.webviewEndpoint!; + const baseEndpoint = this.externalEndpoint || this.environmentService.options!.webviewEndpoint!; const endpoint = baseEndpoint.replace('{{uuid}}', this.id); if (endpoint[endpoint.length - 1] === '/') { return endpoint.slice(0, endpoint.length - 1); @@ -153,6 +153,19 @@ export class IFrameWebview extends Disposable implements Webview { return endpoint; } + private get externalEndpoint(): string | undefined { + const useExternalEndpoint = this.useExternalEndpoint; + if (!useExternalEndpoint) { + return undefined; + } + const commit = product.quality && product.commit ? product.commit : '211fa02efe8c041fd7baa8ec3dce199d5185aa44'; + return `https://{{uuid}}.vscode-webview-test.com/${commit}`; + } + + private get useExternalEndpoint(): boolean { + return isWeb || this._configurationService.getValue('webview.experimental.useExternalEndpoint'); + } + public mountTo(parent: HTMLElement) { if (this.element) { parent.appendChild(this.element); @@ -231,6 +244,10 @@ export class IFrameWebview extends Disposable implements Webview { private readonly _onMessage = this._register(new Emitter()); public readonly onMessage = this._onMessage.event; + private readonly _onMissingCsp = this._register(new Emitter()); + public readonly onMissingCsp = this._onMissingCsp.event; + + sendMessage(data: any): void { this._send('message', data); } diff --git a/src/vs/workbench/contrib/webview/browser/webviewFindWidget.ts b/src/vs/workbench/contrib/webview/browser/webviewFindWidget.ts index 003192f244..fda2bbf4ad 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewFindWidget.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewFindWidget.ts @@ -7,8 +7,10 @@ import { SimpleFindWidget } from 'vs/workbench/contrib/codeEditor/browser/find/s import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED } from 'vs/workbench/contrib/webview/browser/webview'; +import { Event } from 'vs/base/common/event'; export interface WebviewFindDelegate { + readonly hasFindResult: Event; find(value: string, previous: boolean): void; startFind(value: string): void; stopFind(keepSelection?: boolean): void; @@ -25,6 +27,10 @@ export class WebviewFindWidget extends SimpleFindWidget { ) { super(contextViewService, contextKeyService); this._findWidgetFocused = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED.bindTo(contextKeyService); + + this._register(_delegate.hasFindResult(hasResult => { + this.updateButtons(hasResult); + })); } public find(previous: boolean) { diff --git a/src/vs/workbench/contrib/webview/browser/webviewService.ts b/src/vs/workbench/contrib/webview/browser/webviewService.ts index 911c3d5424..c4953c13cf 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewService.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewService.ts @@ -10,7 +10,7 @@ import { DynamicWebviewEditorOverlay } from './dynamicWebviewEditorOverlay'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class WebviewService implements IWebviewService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index 1b18a98f04..e8eef6536e 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -13,17 +13,18 @@ import { URI } from 'vs/base/common/uri'; import * as modes from 'vs/editor/common/modes'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITunnelService } from 'vs/platform/remote/common/tunnel'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; +import { Webview, WebviewContentOptions, WebviewOptions, WebviewResourceScheme } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewPortMappingManager } from 'vs/workbench/contrib/webview/common/portMapping'; import { getWebviewThemeData } from 'vs/workbench/contrib/webview/common/themeing'; -import { Webview, WebviewContentOptions, WebviewOptions, WebviewResourceScheme } from 'vs/workbench/contrib/webview/browser/webview'; import { registerFileProtocol } from 'vs/workbench/contrib/webview/electron-browser/webviewProtocols'; import { areWebviewInputOptionsEqual } from '../browser/webviewEditorService'; -import { WebviewFindWidget } from '../browser/webviewFindWidget'; +import { WebviewFindWidget, WebviewFindDelegate } from '../browser/webviewFindWidget'; interface IKeydownEvent { key: string; @@ -219,7 +220,7 @@ interface WebviewContent { readonly state: string | undefined; } -export class ElectronWebviewBasedWebview extends Disposable implements Webview { +export class ElectronWebviewBasedWebview extends Disposable implements Webview, WebviewFindDelegate { private _webview: Electron.WebviewTag | undefined; private _ready: Promise; @@ -376,12 +377,17 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview { return; } })); + this._register(addDisposableListener(this._webview, 'devtools-opened', () => { this._send('devtools-opened'); })); if (_options.enableFindWidget) { this._webviewFindWidget = this._register(instantiationService.createInstance(WebviewFindWidget, this)); + + this._register(addDisposableListener(this._webview, 'found-in-page', e => { + this._hasFindResult.fire(e.result.matches > 0); + })); } this.style(themeService.getTheme()); @@ -426,6 +432,9 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview { private readonly _onMessage = this._register(new Emitter()); public readonly onMessage = this._onMessage.event; + private readonly _onMissingCsp = this._register(new Emitter()); + public readonly onMissingCsp = this._onMissingCsp.event; + private _send(channel: string, data?: any): void { this._ready .then(() => { @@ -522,7 +531,7 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview { if (this._options.extension && this._options.extension.id) { if (this._environementService.isExtensionDevelopment) { - console.warn(`${this._options.extension.id.value} created a webview without a content security policy: https://aka.ms/vscode-webview-missing-csp`); + this._onMissingCsp.fire(this._options.extension.id); } type TelemetryClassification = { @@ -572,6 +581,9 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview { }); } + private readonly _hasFindResult = this._register(new Emitter()); + public readonly hasFindResult: Event = this._hasFindResult.event; + public startFind(value: string, options?: Electron.FindInPageOptions) { if (!value || !this._webview) { return; @@ -619,6 +631,7 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview { } public stopFind(keepSelection?: boolean): void { + this._hasFindResult.fire(false); if (!this._webview) { return; } diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts index e2e414341f..d2735ff344 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts @@ -11,7 +11,7 @@ import { IWebviewService, WebviewContentOptions, WebviewEditorOverlay, WebviewEl import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; export class ElectronWebviewService implements IWebviewService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts b/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts index f8c00b6abf..5ffcaf7a6c 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts @@ -22,8 +22,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; export class TelemetryOptOut implements IWorkbenchContribution { private static TELEMETRY_OPT_OUT_SHOWN = 'workbench.telemetryOptOutShown'; - private privacyUrl: string; - private optOutUrl: string; + private privacyUrl: string | undefined; constructor( @IStorageService storageService: IStorageService, @@ -50,7 +49,6 @@ export class TelemetryOptOut implements IWorkbenchContribution { } storageService.store(TelemetryOptOut.TELEMETRY_OPT_OUT_SHOWN, true, StorageScope.GLOBAL); - this.optOutUrl = product.telemetryOptOutUrl; this.privacyUrl = product.privacyStatementUrl || product.telemetryOptOutUrl; if (experimentState && experimentState.state === ExperimentState.Run && telemetryService.isOptedIn) { @@ -58,19 +56,21 @@ export class TelemetryOptOut implements IWorkbenchContribution { return; } - // {{SQL CARBON EDIT}} - const optOutNotice = localize('telemetryOptOut.optOutNotice', "Help improve Azure Data Studio by allowing Microsoft to collect usage data. Read our [privacy statement]({0}) and learn how to [opt out]({1}).", this.privacyUrl, this.optOutUrl); - const optInNotice = localize('telemetryOptOut.optInNotice', "Help improve Azure Data Studio by allowing Microsoft to collect usage data. Read our [privacy statement]({0}) and learn how to [opt in]({1}).", this.privacyUrl, this.optOutUrl); + const telemetryOptOutUrl = product.telemetryOptOutUrl; + if (telemetryOptOutUrl) { + const optOutNotice = localize('telemetryOptOut.optOutNotice', "Help improve Azure Data Studio by allowing Microsoft to collect usage data. Read our [privacy statement]({0}) and learn how to [opt out]({1}).", this.privacyUrl, product.telemetryOptOutUrl); // {{SQL CARBON EDIT}} VScode to ads + const optInNotice = localize('telemetryOptOut.optInNotice', "Help improve Azure Data Studio by allowing Microsoft to collect usage data. Read our [privacy statement]({0}) and learn how to [opt in]({1}).", this.privacyUrl, product.telemetryOptOutUrl); // {{SQL CARBON EDIT}} VScode to ads - notificationService.prompt( - Severity.Info, - telemetryService.isOptedIn ? optOutNotice : optInNotice, - [{ - label: localize('telemetryOptOut.readMore', "Read More"), - run: () => openerService.open(URI.parse(this.optOutUrl)) - }], - { sticky: true } - ); + notificationService.prompt( + Severity.Info, + telemetryService.isOptedIn ? optOutNotice : optInNotice, + [{ + label: localize('telemetryOptOut.readMore', "Read More"), + run: () => openerService.open(URI.parse(telemetryOptOutUrl)) + }], + { sticky: true } + ); + } }) .then(undefined, onUnexpectedError); } diff --git a/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts b/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts index 6320295b3b..817e506588 100644 --- a/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts +++ b/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts @@ -153,7 +153,7 @@ export class HideWelcomeOverlayAction extends Action { class WelcomeOverlay extends Disposable { private _overlayVisible: IContextKey; - private _overlay: HTMLElement; + private _overlay!: HTMLElement; constructor( @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts index b1acd7d532..b1e2127956 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts @@ -26,7 +26,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { Event } from 'vs/base/common/event'; import { isObject } from 'vs/base/common/types'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { registerColor, focusBorder, textLinkForeground, textLinkActiveForeground, textPreformatForeground, contrastBorder, textBlockQuoteBackground, textBlockQuoteBorder } from 'vs/platform/theme/common/colorRegistry'; import { getExtraColor } from 'vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils'; @@ -251,7 +251,7 @@ export class WalkThroughPart extends BaseEditor { this.scrollbar.setScrollPosition({ scrollTop: scrollPosition.scrollTop + scrollDimensions.height }); } - setInput(input: WalkThroughInput, options: EditorOptions, token: CancellationToken): Promise { + setInput(input: WalkThroughInput, options: EditorOptions | undefined, token: CancellationToken): Promise { if (this.input instanceof WalkThroughInput) { this.saveTextEditorViewState(this.input); } @@ -312,7 +312,7 @@ export class WalkThroughPart extends BaseEditor { this.contentDisposables.push(editor); const updateHeight = (initial: boolean) => { - const lineHeight = editor.getConfiguration().lineHeight; + const lineHeight = editor.getOption(EditorOption.lineHeight); const height = `${Math.max(model.getLineCount() + 1, 4) * lineHeight}px`; if (div.style.height !== height) { div.style.height = height; @@ -329,7 +329,7 @@ export class WalkThroughPart extends BaseEditor { if (innerContent) { const targetTop = div.getBoundingClientRect().top; const containerTop = innerContent.getBoundingClientRect().top; - const lineHeight = editor.getConfiguration().lineHeight; + const lineHeight = editor.getOption(EditorOption.lineHeight); const lineTop = (targetTop + (e.position.lineNumber - 1) * lineHeight) - containerTop; const lineBottom = lineTop + lineHeight; const scrollDimensions = this.scrollbar.getScrollDimensions(); diff --git a/src/vs/workbench/electron-browser/actions/helpActions.ts b/src/vs/workbench/electron-browser/actions/helpActions.ts index a9394d45bc..b3d74d1d04 100644 --- a/src/vs/workbench/electron-browser/actions/helpActions.ts +++ b/src/vs/workbench/electron-browser/actions/helpActions.ts @@ -28,7 +28,9 @@ export class KeybindingsReferenceAction extends Action { } run(): Promise { - this.openerService.open(URI.parse(KeybindingsReferenceAction.URL)); + if (KeybindingsReferenceAction.URL) { + this.openerService.open(URI.parse(KeybindingsReferenceAction.URL)); + } return Promise.resolve(); } @@ -51,7 +53,9 @@ export class OpenDocumentationUrlAction extends Action { } run(): Promise { - this.openerService.open(URI.parse(OpenDocumentationUrlAction.URL)); + if (OpenDocumentationUrlAction.URL) { + this.openerService.open(URI.parse(OpenDocumentationUrlAction.URL)); + } return Promise.resolve(); } @@ -74,7 +78,9 @@ export class OpenIntroductoryVideosUrlAction extends Action { } run(): Promise { - this.openerService.open(URI.parse(OpenIntroductoryVideosUrlAction.URL)); + if (OpenIntroductoryVideosUrlAction.URL) { + this.openerService.open(URI.parse(OpenIntroductoryVideosUrlAction.URL)); + } return Promise.resolve(); } @@ -97,7 +103,10 @@ export class OpenTipsAndTricksUrlAction extends Action { } run(): Promise { - this.openerService.open(URI.parse(OpenTipsAndTricksUrlAction.URL)); + if (OpenTipsAndTricksUrlAction.URL) { + this.openerService.open(URI.parse(OpenTipsAndTricksUrlAction.URL)); + } + return Promise.resolve(); } } @@ -106,31 +115,29 @@ export class OpenNewsletterSignupUrlAction extends Action { static readonly ID = 'workbench.action.openNewsletterSignupUrl'; static readonly LABEL = nls.localize('newsletterSignup', "Signup for the VS Code Newsletter"); - private telemetryService: ITelemetryService; - private static readonly URL = product.newsletterSignupUrl; - static readonly AVAILABLE = !!OpenNewsletterSignupUrlAction.URL; + static readonly AVAILABLE = !!product.newsletterSignupUrl; constructor( id: string, label: string, @IOpenerService private readonly openerService: IOpenerService, - @ITelemetryService telemetryService: ITelemetryService + @ITelemetryService private readonly telemetryService: ITelemetryService ) { super(id, label); - this.telemetryService = telemetryService; } async run(): Promise { const info = await this.telemetryService.getTelemetryInfo(); - this.openerService.open(URI.parse(`${OpenNewsletterSignupUrlAction.URL}?machineId=${encodeURIComponent(info.machineId)}`)); + this.openerService.open(URI.parse(`${product.newsletterSignupUrl}?machineId=${encodeURIComponent(info.machineId)}`)); } } export class OpenTwitterUrlAction extends Action { static readonly ID = 'workbench.action.openTwitterUrl'; - static LABEL = nls.localize('openTwitterUrl', "Join Us on Twitter", product.applicationName); + static readonly LABEL = nls.localize('openTwitterUrl', "Join Us on Twitter", product.applicationName); + static readonly AVAILABLE = !!product.twitterUrl; constructor( id: string, @@ -152,7 +159,8 @@ export class OpenTwitterUrlAction extends Action { export class OpenRequestFeatureUrlAction extends Action { static readonly ID = 'workbench.action.openRequestFeatureUrl'; - static LABEL = nls.localize('openUserVoiceUrl', "Search Feature Requests"); + static readonly LABEL = nls.localize('openUserVoiceUrl', "Search Feature Requests"); + static readonly AVAILABLE = !!product.requestFeatureUrl; constructor( id: string, @@ -174,7 +182,8 @@ export class OpenRequestFeatureUrlAction extends Action { export class OpenLicenseUrlAction extends Action { static readonly ID = 'workbench.action.openLicenseUrl'; - static LABEL = nls.localize('openLicenseUrl', "View License"); + static readonly LABEL = nls.localize('openLicenseUrl', "View License"); + static readonly AVAILABLE = !!product.licenseUrl; constructor( id: string, @@ -201,7 +210,8 @@ export class OpenLicenseUrlAction extends Action { export class OpenPrivacyStatementUrlAction extends Action { static readonly ID = 'workbench.action.openPrivacyStatementUrl'; - static LABEL = nls.localize('openPrivacyStatement', "Privacy Statement"); + static readonly LABEL = nls.localize('openPrivacyStatement', "Privacy Statement"); + static readonly AVAILABE = !!product.privacyStatementUrl; constructor( id: string, diff --git a/src/vs/workbench/electron-browser/desktop.contribution.ts b/src/vs/workbench/electron-browser/desktop.contribution.ts index 5fe3e06edb..605cfa64a7 100644 --- a/src/vs/workbench/electron-browser/desktop.contribution.ts +++ b/src/vs/workbench/electron-browser/desktop.contribution.ts @@ -148,10 +148,21 @@ import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/browser/exten registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNewsletterSignupUrlAction, OpenNewsletterSignupUrlAction.ID, OpenNewsletterSignupUrlAction.LABEL), 'Help: Tips and Tricks', helpCategory); } - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenTwitterUrlAction, OpenTwitterUrlAction.ID, OpenTwitterUrlAction.LABEL), 'Help: Join Us on Twitter', helpCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenRequestFeatureUrlAction, OpenRequestFeatureUrlAction.ID, OpenRequestFeatureUrlAction.LABEL), 'Help: Search Feature Requests', helpCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenLicenseUrlAction, OpenLicenseUrlAction.ID, OpenLicenseUrlAction.LABEL), 'Help: View License', helpCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPrivacyStatementUrlAction, OpenPrivacyStatementUrlAction.ID, OpenPrivacyStatementUrlAction.LABEL), 'Help: Privacy Statement', helpCategory); + if (OpenTwitterUrlAction.AVAILABLE) { + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenTwitterUrlAction, OpenTwitterUrlAction.ID, OpenTwitterUrlAction.LABEL), 'Help: Join Us on Twitter', helpCategory); + } + + if (OpenRequestFeatureUrlAction.AVAILABLE) { + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenRequestFeatureUrlAction, OpenRequestFeatureUrlAction.ID, OpenRequestFeatureUrlAction.LABEL), 'Help: Search Feature Requests', helpCategory); + } + + if (OpenLicenseUrlAction.AVAILABLE) { + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenLicenseUrlAction, OpenLicenseUrlAction.ID, OpenLicenseUrlAction.LABEL), 'Help: View License', helpCategory); + } + + if (OpenPrivacyStatementUrlAction.AVAILABE) { + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPrivacyStatementUrlAction, OpenPrivacyStatementUrlAction.ID, OpenPrivacyStatementUrlAction.LABEL), 'Help: Privacy Statement', helpCategory); + } })(); })(); @@ -266,14 +277,16 @@ import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/browser/exten // Help - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '1_welcome', - command: { - id: OpenDocumentationUrlAction.ID, - title: nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation") - }, - order: 3 - }); + if (OpenDocumentationUrlAction.AVAILABLE) { + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '1_welcome', + command: { + id: OpenDocumentationUrlAction.ID, + title: nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation") + }, + order: 3 + }); + } /* // {{SQL CARBON EDIT}} - Disable unused menu item MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { @@ -286,51 +299,61 @@ import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/browser/exten }); // Reference - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '2_reference', - command: { - id: KeybindingsReferenceAction.ID, - title: nls.localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference") - }, - order: 1 - }); + if (KeybindingsReferenceAction.AVAILABLE) { + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '2_reference', + command: { + id: KeybindingsReferenceAction.ID, + title: nls.localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference") + }, + order: 1 + }); + } - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '2_reference', - command: { - id: OpenIntroductoryVideosUrlAction.ID, - title: nls.localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos") - }, - order: 2 - }); + if (OpenIntroductoryVideosUrlAction.AVAILABLE) { + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '2_reference', + command: { + id: OpenIntroductoryVideosUrlAction.ID, + title: nls.localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos") + }, + order: 2 + }); + } - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '2_reference', - command: { - id: OpenTipsAndTricksUrlAction.ID, - title: nls.localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "Tips and Tri&&cks") - }, - order: 3 - }); + if (OpenTipsAndTricksUrlAction.AVAILABLE) { + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '2_reference', + command: { + id: OpenTipsAndTricksUrlAction.ID, + title: nls.localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "Tips and Tri&&cks") + }, + order: 3 + }); + } // Feedback - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '3_feedback', - command: { - id: OpenTwitterUrlAction.ID, - title: nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join Us on Twitter") - }, - order: 1 - }); + if (OpenTwitterUrlAction.AVAILABLE) { + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '3_feedback', + command: { + id: OpenTwitterUrlAction.ID, + title: nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join Us on Twitter") + }, + order: 1 + }); + } - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '3_feedback', - command: { - id: OpenRequestFeatureUrlAction.ID, - title: nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests") - }, - order: 2 - }); + if (OpenRequestFeatureUrlAction.AVAILABLE) { + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '3_feedback', + command: { + id: OpenRequestFeatureUrlAction.ID, + title: nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests") + }, + order: 2 + }); + } */ MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { @@ -343,23 +366,27 @@ import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/browser/exten }); // Legal - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '4_legal', - command: { - id: OpenLicenseUrlAction.ID, - title: nls.localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "View &&License") - }, - order: 1 - }); + if (OpenLicenseUrlAction.AVAILABLE) { + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '4_legal', + command: { + id: OpenLicenseUrlAction.ID, + title: nls.localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "View &&License") + }, + order: 1 + }); + } - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '4_legal', - command: { - id: OpenPrivacyStatementUrlAction.ID, - title: nls.localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "Privac&&y Statement") - }, - order: 2 - }); + if (OpenPrivacyStatementUrlAction.AVAILABE) { + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '4_legal', + command: { + id: OpenPrivacyStatementUrlAction.ID, + title: nls.localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "Privac&&y Statement") + }, + order: 2 + }); + } // Tools MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 9cfbb6d9a4..5631818262 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -70,12 +70,11 @@ const TextInputActions: IAction[] = [ export class ElectronWindow extends Disposable { - private touchBarMenu?: IMenu; - private touchBarUpdater: RunOnceScheduler; + private touchBarMenu: IMenu | undefined; private readonly touchBarDisposables = this._register(new DisposableStore()); - private lastInstalledTouchedBar: ICommandAction[][]; + private lastInstalledTouchedBar: ICommandAction[][] | undefined; - private previousConfiguredZoomLevel: number; + private previousConfiguredZoomLevel: number | undefined; private addFoldersScheduler: RunOnceScheduler; private pendingFoldersToAdd: URI[]; @@ -325,24 +324,21 @@ export class ElectronWindow extends Disposable { this.integrityService.isPure().then(res => this.titleService.updateProperties({ isPure: res.isPure })); // Root warning - this.lifecycleService.when(LifecyclePhase.Restored).then(() => { - let isAdminPromise: Promise; + this.lifecycleService.when(LifecyclePhase.Restored).then(async () => { + let isAdmin: boolean; if (isWindows) { - isAdminPromise = import('native-is-elevated').then(isElevated => isElevated()); // not using async here due to https://github.com/microsoft/vscode/issues/74321 + isAdmin = (await import('native-is-elevated'))(); } else { - isAdminPromise = Promise.resolve(isRootUser()); + isAdmin = isRootUser(); } - return isAdminPromise.then(isAdmin => { + // Update title + this.titleService.updateProperties({ isAdmin }); - // Update title - this.titleService.updateProperties({ isAdmin }); - - // Show warning message (unix only) - if (isAdmin && !isWindows) { - this.notificationService.warn(nls.localize('runningAsRoot', "It is not recommended to run {0} as root user.", product.nameShort)); - } - }); + // Show warning message (unix only) + if (isAdmin && !isWindows) { + this.notificationService.warn(nls.localize('runningAsRoot', "It is not recommended to run {0} as root user.", product.nameShort)); + } }); // Touchbar menu (if enabled) @@ -350,7 +346,7 @@ export class ElectronWindow extends Disposable { // Crash reporter (if enabled) if (!this.environmentService.disableCrashReporter && product.crashReporter && product.hockeyApp && this.configurationService.getValue('telemetry.enableCrashReporter')) { - this.setupCrashReporter(); + this.setupCrashReporter(product.crashReporter.companyName, product.crashReporter.productName, product.hockeyApp); } } @@ -397,16 +393,15 @@ export class ElectronWindow extends Disposable { this.touchBarMenu = undefined; // Create new (delayed) - this.touchBarUpdater = new RunOnceScheduler(() => this.doUpdateTouchbarMenu(), 300); - this.touchBarDisposables.add(this.touchBarUpdater); - this.touchBarUpdater.schedule(); + const scheduler: RunOnceScheduler = this.touchBarDisposables.add(new RunOnceScheduler(() => this.doUpdateTouchbarMenu(scheduler), 300)); + scheduler.schedule(); } - private doUpdateTouchbarMenu(): void { + private doUpdateTouchbarMenu(scheduler: RunOnceScheduler): void { if (!this.touchBarMenu) { this.touchBarMenu = this.editorService.invokeWithinEditorContext(accessor => this.menuService.createMenu(MenuId.TouchBarContext, accessor.get(IContextKeyService))); this.touchBarDisposables.add(this.touchBarMenu); - this.touchBarDisposables.add(this.touchBarMenu.onDidChange(() => this.touchBarUpdater.schedule())); + this.touchBarDisposables.add(this.touchBarMenu.onDidChange(() => scheduler.schedule())); } const actions: Array = []; @@ -454,13 +449,16 @@ export class ElectronWindow extends Disposable { } } - private async setupCrashReporter(): Promise { + private async setupCrashReporter(companyName: string, productName: string, hockeyAppConfig: typeof product.hockeyApp): Promise { + if (!hockeyAppConfig) { + return; + } // base options with product info const options = { - companyName: product.crashReporter.companyName, - productName: product.crashReporter.productName, - submitURL: isWindows ? product.hockeyApp[process.arch === 'ia32' ? 'win32-ia32' : 'win32-x64'] : isLinux ? product.hockeyApp[`linux-x64`] : product.hockeyApp.darwin, + companyName, + productName, + submitURL: isWindows ? hockeyAppConfig[process.arch === 'ia32' ? 'win32-ia32' : 'win32-x64'] : isLinux ? hockeyAppConfig[`linux-x64`] : hockeyAppConfig.darwin, extra: { vscode_version: pkg.version, vscode_commit: product.commit diff --git a/src/vs/workbench/services/accessibility/node/accessibilityService.ts b/src/vs/workbench/services/accessibility/node/accessibilityService.ts index 1752979cd4..f141ab6d0e 100644 --- a/src/vs/workbench/services/accessibility/node/accessibilityService.ts +++ b/src/vs/workbench/services/accessibility/node/accessibilityService.ts @@ -10,11 +10,10 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { AbstractAccessibilityService } from 'vs/platform/accessibility/common/abstractAccessibilityService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class AccessibilityService extends AbstractAccessibilityService implements IAccessibilityService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private _accessibilitySupport = AccessibilitySupport.Unknown; diff --git a/src/vs/workbench/services/activity/browser/activityService.ts b/src/vs/workbench/services/activity/browser/activityService.ts index aedbcecc22..c71a257c66 100644 --- a/src/vs/workbench/services/activity/browser/activityService.ts +++ b/src/vs/workbench/services/activity/browser/activityService.ts @@ -11,7 +11,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class ActivityService implements IActivityService { - public _serviceBrand: any; + public _serviceBrand: undefined; constructor( @IPanelService private readonly panelService: IPanelService, diff --git a/src/vs/workbench/services/activity/common/activity.ts b/src/vs/workbench/services/activity/common/activity.ts index b8554edef7..4bd41bca7e 100644 --- a/src/vs/workbench/services/activity/common/activity.ts +++ b/src/vs/workbench/services/activity/common/activity.ts @@ -58,7 +58,7 @@ export class ProgressBadge extends BaseBadge { } export const IActivityService = createDecorator('activityService'); export interface IActivityService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Show activity in the panel for the given panel or in the activitybar for the given viewlet or global action. diff --git a/src/vs/workbench/services/activityBar/browser/activityBarService.ts b/src/vs/workbench/services/activityBar/browser/activityBarService.ts index 7146adc8c4..cfb274d9a5 100644 --- a/src/vs/workbench/services/activityBar/browser/activityBarService.ts +++ b/src/vs/workbench/services/activityBar/browser/activityBarService.ts @@ -10,7 +10,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; export const IActivityBarService = createDecorator('activityBarService'); export interface IActivityBarService { - _serviceBrand: any; + _serviceBrand: undefined; /** * Show an activity in a viewlet. diff --git a/src/vs/workbench/services/backup/common/backup.ts b/src/vs/workbench/services/backup/common/backup.ts index ccc26b0b63..e07605e486 100644 --- a/src/vs/workbench/services/backup/common/backup.ts +++ b/src/vs/workbench/services/backup/common/backup.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ITextBufferFactory, ITextSnapshot } from 'vs/editor/common/model'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { joinPath, relativePath } from 'vs/base/common/resources'; @@ -21,7 +21,7 @@ export interface IResolvedBackup { */ export interface IBackupFileService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; /** * Finds out if there are any backups stored. @@ -91,4 +91,4 @@ export interface IBackupFileService { export function toBackupWorkspaceResource(backupWorkspacePath: string, environmentService: IEnvironmentService): URI { return joinPath(environmentService.userRoamingDataHome, relativePath(URI.file(environmentService.userDataPath), URI.file(backupWorkspacePath))!); -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/backup/common/backupFileService.ts b/src/vs/workbench/services/backup/common/backupFileService.ts index b3f74b48cc..26a46a7e4d 100644 --- a/src/vs/workbench/services/backup/common/backupFileService.ts +++ b/src/vs/workbench/services/backup/common/backupFileService.ts @@ -19,7 +19,6 @@ import { Schemas } from 'vs/base/common/network'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { VSBuffer } from 'vs/base/common/buffer'; import { TextSnapshotReadable } from 'vs/workbench/services/textfile/common/textfiles'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export interface IBackupFilesModel { resolve(backupRoot: URI): Promise; @@ -106,7 +105,7 @@ export class BackupFilesModel implements IBackupFilesModel { export class BackupFileService implements IBackupFileService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private impl: IBackupFileService; @@ -114,7 +113,7 @@ export class BackupFileService implements IBackupFileService { @IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService, @IFileService protected fileService: IFileService ) { - this.initialize(); + this.impl = this.initialize(); } protected hashPath(resource: URI): string { @@ -123,13 +122,13 @@ export class BackupFileService implements IBackupFileService { return hash(str).toString(16); } - private initialize(): void { + private initialize(): IBackupFileService { const backupWorkspaceResource = this.environmentService.configuration.backupWorkspaceResource; if (backupWorkspaceResource) { - this.impl = new BackupFileServiceImpl(backupWorkspaceResource, this.hashPath, this.fileService); - } else { - this.impl = new InMemoryBackupFileService(this.hashPath); + return new BackupFileServiceImpl(backupWorkspaceResource, this.hashPath, this.fileService); } + + return new InMemoryBackupFileService(this.hashPath); } reinitialize(): void { @@ -188,7 +187,7 @@ class BackupFileServiceImpl implements IBackupFileService { private static readonly PREAMBLE_META_SEPARATOR = ' '; // using a character that is know to be escaped in a URI as separator private static readonly PREAMBLE_MAX_LENGTH = 10000; - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private backupWorkspacePath!: URI; @@ -398,7 +397,7 @@ class BackupFileServiceImpl implements IBackupFileService { export class InMemoryBackupFileService implements IBackupFileService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private backups: Map = new Map(); diff --git a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts index c69d9c2dc2..c8d928dd88 100644 --- a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts +++ b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts @@ -21,7 +21,7 @@ import { FileService } from 'vs/platform/files/common/fileService'; import { NullLogService } from 'vs/platform/log/common/log'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; import { IFileService } from 'vs/platform/files/common/files'; import { hashPath, BackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; @@ -49,7 +49,7 @@ const untitledBackupPath = path.join(workspaceBackupPath, 'untitled', hashPath(u class TestBackupEnvironmentService extends WorkbenchEnvironmentService { constructor(backupPath: string) { - super({ ...parseArgs(process.argv), ...{ backupPath, 'user-data-dir': userdataDir } } as IWindowConfiguration, process.execPath); + super({ ...parseArgs(process.argv, OPTIONS), ...{ backupPath, 'user-data-dir': userdataDir } } as IWindowConfiguration, process.execPath); } } diff --git a/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts b/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts index 49122775d5..c132e63e7a 100644 --- a/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts +++ b/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts @@ -23,6 +23,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ILabelService } from 'vs/platform/label/common/label'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; abstract class Recording { @@ -374,7 +375,7 @@ export class BulkEdit { export class BulkEditService implements IBulkEditService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @ILogService private readonly _logService: ILogService, @@ -414,7 +415,7 @@ export class BulkEditService implements IBulkEditService { } } - if (codeEditor && codeEditor.getConfiguration().readOnly) { + if (codeEditor && codeEditor.getOption(EditorOption.readOnly)) { // If the code editor is readonly still allow bulk edits to be applied #68549 codeEditor = undefined; } diff --git a/src/vs/workbench/services/commands/common/commandService.ts b/src/vs/workbench/services/commands/common/commandService.ts index 7d5801ef04..2faa41e22b 100644 --- a/src/vs/workbench/services/commands/common/commandService.ts +++ b/src/vs/workbench/services/commands/common/commandService.ts @@ -14,7 +14,7 @@ import { timeout } from 'vs/base/common/async'; export class CommandService extends Disposable implements ICommandService { - _serviceBrand: any; + _serviceBrand: undefined; private _extensionHostIsReady: boolean = false; private _starActivation: Promise | null; diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index 2a01110a82..4fe01635bc 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -6,7 +6,7 @@ import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { ResourceMap } from 'vs/base/common/map'; -import { equals, deepClone } from 'vs/base/common/objects'; +import { equals } from 'vs/base/common/objects'; import { Disposable } from 'vs/base/common/lifecycle'; import { Queue, Barrier } from 'vs/base/common/async'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; @@ -16,13 +16,13 @@ import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides 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 } 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 { IConfigurationRegistry, Extensions, allSettings, windowSettings, resourceSettings, applicationSettings, machineSettings, machineOverridableSettings } 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'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ConfigurationEditingService, EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditingService'; import { WorkspaceConfiguration, FolderConfiguration, RemoteUserConfiguration, UserConfiguration } from 'vs/workbench/services/configuration/browser/configuration'; import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService'; -import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; +import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { isEqual, dirname } from 'vs/base/common/resources'; import { mark } from 'vs/base/common/performance'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; @@ -31,7 +31,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ export class WorkspaceService extends Disposable implements IConfigurationService, IWorkspaceContextService { - public _serviceBrand: any; + public _serviceBrand: undefined; private workspace: Workspace; private completeWorkspaceBarrier: Barrier; @@ -491,6 +491,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic if (this.workspace) { this._configuration.updateDefaultConfiguration(this.defaultConfiguration); if (this.remoteUserConfiguration) { + this._configuration.updateLocalUserConfiguration(this.localUserConfiguration.reprocess()); this._configuration.updateRemoteUserConfiguration(this.remoteUserConfiguration.reprocess()); } if (this.getWorkbenchState() === WorkbenchState.FOLDER) { @@ -506,29 +507,17 @@ export class WorkspaceService extends Disposable implements IConfigurationServic private registerConfigurationSchemas(): void { if (this.workspace) { const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); - const convertToNotSuggestedProperties = (properties: IJSONSchemaMap): IJSONSchemaMap => { - return Object.keys(properties).reduce((result: IJSONSchemaMap, property) => { - result[property] = deepClone(properties[property]); - result[property].doNotSuggest = true; - return result; - }, {}); - }; - - const unsupportedApplicationSettings = convertToNotSuggestedProperties(applicationSettings.properties); - const unsupportedMachineSettings = convertToNotSuggestedProperties(machineSettings.properties); - const unsupportedRemoteMachineSettings = convertToNotSuggestedProperties(machineSettings.properties); - const allSettingsSchema: IJSONSchema = { properties: allSettings.properties, patternProperties: allSettings.patternProperties, additionalProperties: true }; - const userSettingsSchema: IJSONSchema = this.remoteUserConfiguration ? { properties: { ...applicationSettings.properties, ...unsupportedRemoteMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true } : allSettingsSchema; - const machineSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true }; - const workspaceSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true }; + const allSettingsSchema: IJSONSchema = { properties: allSettings.properties, patternProperties: allSettings.patternProperties, additionalProperties: true, allowsTrailingCommas: true, allowComments: true }; + const userSettingsSchema: IJSONSchema = this.remoteUserConfiguration ? { properties: { ...applicationSettings.properties, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true, allowsTrailingCommas: true, allowComments: true } : allSettingsSchema; + const machineSettingsSchema: IJSONSchema = { properties: { ...machineSettings.properties, ...machineOverridableSettings.properties, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true, allowsTrailingCommas: true, allowComments: true }; + const workspaceSettingsSchema: IJSONSchema = { properties: { ...machineOverridableSettings.properties, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true, allowsTrailingCommas: true, allowComments: true }; jsonRegistry.registerSchema(defaultSettingsSchemaId, allSettingsSchema); jsonRegistry.registerSchema(userSettingsSchemaId, userSettingsSchema); jsonRegistry.registerSchema(machineSettingsSchemaId, machineSettingsSchema); if (WorkbenchState.WORKSPACE === this.getWorkbenchState()) { - const unsupportedWindowSettings = convertToNotSuggestedProperties(windowSettings.properties); - const folderSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...unsupportedWindowSettings, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true }; + const folderSettingsSchema: IJSONSchema = { properties: { ...machineOverridableSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true, allowsTrailingCommas: true, allowComments: true }; jsonRegistry.registerSchema(workspaceSettingsSchemaId, workspaceSettingsSchema); jsonRegistry.registerSchema(folderSettingsSchemaId, folderSettingsSchema); } else { @@ -724,4 +713,4 @@ export class WorkspaceService extends Disposable implements IConfigurationServic } return null; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/configuration/common/configurationEditingService.ts b/src/vs/workbench/services/configuration/common/configurationEditingService.ts index 34408c4e22..db2853ceda 100644 --- a/src/vs/workbench/services/configuration/common/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/common/configurationEditingService.ts @@ -130,7 +130,7 @@ interface ConfigurationEditingOptions extends IConfigurationEditingOptions { export class ConfigurationEditingService { - public _serviceBrand: any; + public _serviceBrand: undefined; private queue: Queue; private remoteSettingsResource: URI | null = null; diff --git a/src/vs/workbench/services/configuration/common/jsonEditing.ts b/src/vs/workbench/services/configuration/common/jsonEditing.ts index ac9ea7ebce..4f1240d555 100644 --- a/src/vs/workbench/services/configuration/common/jsonEditing.ts +++ b/src/vs/workbench/services/configuration/common/jsonEditing.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export const IJSONEditingService = createDecorator('jsonEditingService'); @@ -34,7 +34,7 @@ export interface IJSONValue { export interface IJSONEditingService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; write(resource: URI, value: IJSONValue, save: boolean): Promise; -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/configuration/common/jsonEditingService.ts b/src/vs/workbench/services/configuration/common/jsonEditingService.ts index 122041d4dd..77e425fe91 100644 --- a/src/vs/workbench/services/configuration/common/jsonEditingService.ts +++ b/src/vs/workbench/services/configuration/common/jsonEditingService.ts @@ -23,7 +23,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class JSONEditingService implements IJSONEditingService { - public _serviceBrand: any; + public _serviceBrand: undefined; private queue: Queue; diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts index 66fb94acc4..3dd2a8b2c1 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts @@ -11,7 +11,7 @@ import * as fs from 'fs'; import * as json from 'vs/base/common/json'; import { Registry } from 'vs/platform/registry/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { TestTextFileService, workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices'; import * as uuid from 'vs/base/common/uuid'; @@ -46,7 +46,7 @@ import { FileUserDataProvider } from 'vs/workbench/services/userData/common/file class TestEnvironmentService extends WorkbenchEnvironmentService { constructor(private _appSettingsHome: URI) { - super(parseArgs(process.argv) as IWindowConfiguration, process.execPath); + super(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath); } get appSettingsHome() { return this._appSettingsHome; } @@ -185,7 +185,7 @@ suite('ConfigurationEditingService', () => { test('do not notify error', () => { instantiationService.stub(ITextFileService, 'isDirty', true); const target = sinon.stub(); - instantiationService.stub(INotificationService, { prompt: target, _serviceBrand: null!, notify: null!, error: null!, info: null!, warn: null!, status: null! }); + instantiationService.stub(INotificationService, { prompt: target, _serviceBrand: undefined, notify: null!, error: null!, info: null!, warn: null!, status: null! }); return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotNotifyError: true }) .then(() => assert.fail('Should fail with ERROR_CONFIGURATION_FILE_DIRTY error.'), (error: ConfigurationEditingError) => { diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts index 65f70f5f5e..a0574238d0 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts @@ -11,7 +11,7 @@ import * as os from 'os'; import { URI } from 'vs/base/common/uri'; import { Registry } from 'vs/platform/registry/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import * as pfs from 'vs/base/node/pfs'; import * as uuid from 'vs/base/common/uuid'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; @@ -51,7 +51,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ class TestEnvironmentService extends WorkbenchEnvironmentService { constructor(private _appSettingsHome: URI) { - super(parseArgs(process.argv) as IWindowConfiguration, process.execPath); + super(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath); } get appSettingsHome() { return this._appSettingsHome; } @@ -735,6 +735,11 @@ suite.skip('WorkspaceConfigurationService - Folder', () => { // {{SQL CARBON EDI 'default': 'isSet', scope: ConfigurationScope.MACHINE }, + 'configurationService.folder.machineOverridableSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE_OVERRIDABLE + }, 'configurationService.folder.testSetting': { 'type': 'string', 'default': 'isSet', @@ -787,7 +792,7 @@ suite.skip('WorkspaceConfigurationService - Folder', () => { // {{SQL CARBON EDI }); test('defaults', () => { - assert.deepEqual(testObject.getValue('configurationService'), { 'folder': { 'applicationSetting': 'isSet', 'machineSetting': 'isSet', 'testSetting': 'isSet' } }); + assert.deepEqual(testObject.getValue('configurationService'), { 'folder': { 'applicationSetting': 'isSet', 'machineSetting': 'isSet', 'machineOverridableSetting': 'isSet', 'testSetting': 'isSet' } }); }); test('globals override defaults', () => { @@ -815,6 +820,13 @@ suite.skip('WorkspaceConfigurationService - Folder', () => { // {{SQL CARBON EDI .then(() => assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'workspaceValue')); }); + test('machine overridable settings override user Settings', () => { + fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.machineOverridableSetting": "userValue" }'); + fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "configurationService.folder.machineOverridableSetting": "workspaceValue" }'); + return testObject.reloadConfiguration() + .then(() => assert.equal(testObject.getValue('configurationService.folder.machineOverridableSetting'), 'workspaceValue')); + }); + test('workspace settings override user settings after defaults are registered ', () => { fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.newSetting": "userValue" }'); fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "configurationService.folder.newSetting": "workspaceValue" }'); @@ -836,6 +848,28 @@ suite.skip('WorkspaceConfigurationService - Folder', () => { // {{SQL CARBON EDI }); }); + test('machine overridable settings override user settings after defaults are registered ', () => { + fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.newMachineOverridableSetting": "userValue" }'); + fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "configurationService.folder.newMachineOverridableSetting": "workspaceValue" }'); + return testObject.reloadConfiguration() + .then(() => { + + configurationRegistry.registerConfiguration({ + 'id': '_test', + 'type': 'object', + 'properties': { + 'configurationService.folder.newMachineOverridableSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE_OVERRIDABLE + } + } + }); + + assert.equal(testObject.getValue('configurationService.folder.newMachineOverridableSetting'), 'workspaceValue'); + }); + }); + test('application settings are not read from workspace', () => { fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.applicationSetting": "userValue" }'); fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "configurationService.folder.applicationSetting": "workspaceValue" }'); @@ -1066,6 +1100,11 @@ suite.skip('WorkspaceConfigurationService-Multiroot', () => { // {{SQL CARBON ED 'default': 'isSet', scope: ConfigurationScope.MACHINE }, + 'configurationService.workspace.machineOverridableSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE_OVERRIDABLE + }, 'configurationService.workspace.testResourceSetting': { 'type': 'string', 'default': 'isSet', @@ -1153,6 +1192,26 @@ suite.skip('WorkspaceConfigurationService-Multiroot', () => { // {{SQL CARBON ED }); }); + test('workspace settings override user settings after defaults are registered for machine overridable settings ', () => { + fs.writeFileSync(globalSettingsFile, '{ "configurationService.workspace.newMachineOverridableSetting": "userValue" }'); + return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.newMachineOverridableSetting': 'workspaceValue' } }, true) + .then(() => testObject.reloadConfiguration()) + .then(() => { + configurationRegistry.registerConfiguration({ + 'id': '_test', + 'type': 'object', + 'properties': { + 'configurationService.workspace.newMachineOverridableSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE_OVERRIDABLE + } + } + }); + assert.equal(testObject.getValue('configurationService.workspace.newMachineOverridableSetting'), 'workspaceValue'); + }); + }); + test('application settings are not read from workspace folder', () => { fs.writeFileSync(globalSettingsFile, '{ "configurationService.workspace.applicationSetting": "userValue" }'); fs.writeFileSync(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json').fsPath, '{ "configurationService.workspace.applicationSetting": "workspaceFolderValue" }'); @@ -1227,6 +1286,26 @@ suite.skip('WorkspaceConfigurationService-Multiroot', () => { // {{SQL CARBON ED }); }); + test('machine overridable setting in folder is read after it is registered later', () => { + fs.writeFileSync(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json').fsPath, '{ "configurationService.workspace.testNewMachineOverridableSetting2": "workspaceFolderValue" }'); + return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.testNewMachineOverridableSetting2': 'workspaceValue' } }, true) + .then(() => testObject.reloadConfiguration()) + .then(() => { + configurationRegistry.registerConfiguration({ + 'id': '_test', + 'type': 'object', + 'properties': { + 'configurationService.workspace.testNewMachineOverridableSetting2': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE_OVERRIDABLE + } + } + }); + assert.equal(testObject.getValue('configurationService.workspace.testNewMachineOverridableSetting2', { resource: workspaceContextService.getWorkspace().folders[0].uri }), 'workspaceFolderValue'); + }); + }); + test('inspect', () => { let actual = testObject.inspect('something.missing'); assert.equal(actual.default, undefined); @@ -1467,6 +1546,11 @@ suite('WorkspaceConfigurationService - Remote Folder', () => { 'default': 'isSet', scope: ConfigurationScope.MACHINE }, + 'configurationService.remote.machineOverridableSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE_OVERRIDABLE + }, 'configurationService.remote.testSetting': { 'type': 'string', 'default': 'isSet', @@ -1616,6 +1700,52 @@ suite('WorkspaceConfigurationService - Remote Folder', () => { assert.equal(testObject.getValue('configurationService.remote.machineSetting'), 'isSet'); }); + test('machine overridable settings in local user settings does not override defaults', async () => { + fs.writeFileSync(globalSettingsFile, '{ "configurationService.remote.machineOverridableSetting": "globalValue" }'); + registerRemoteFileSystemProvider(); + resolveRemoteEnvironment(); + await initialize(); + assert.equal(testObject.getValue('configurationService.remote.machineOverridableSetting'), 'isSet'); + }); + + test('machine settings in local user settings does not override defaults after defalts are registered ', async () => { + fs.writeFileSync(globalSettingsFile, '{ "configurationService.remote.newMachineSetting": "userValue" }'); + registerRemoteFileSystemProvider(); + resolveRemoteEnvironment(); + await initialize(); + configurationRegistry.registerConfiguration({ + 'id': '_test', + 'type': 'object', + 'properties': { + 'configurationService.remote.newMachineSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE + } + } + }); + assert.equal(testObject.getValue('configurationService.remote.newMachineSetting'), 'isSet'); + }); + + test('machine overridable settings in local user settings does not override defaults after defalts are registered ', async () => { + fs.writeFileSync(globalSettingsFile, '{ "configurationService.remote.newMachineOverridableSetting": "userValue" }'); + registerRemoteFileSystemProvider(); + resolveRemoteEnvironment(); + await initialize(); + configurationRegistry.registerConfiguration({ + 'id': '_test', + 'type': 'object', + 'properties': { + 'configurationService.remote.newMachineOverridableSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE_OVERRIDABLE + } + } + }); + assert.equal(testObject.getValue('configurationService.remote.newMachineOverridableSetting'), 'isSet'); + }); + }); function getWorkspaceId(configPath: URI): string { diff --git a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts index fcc2f287a1..2c9b197a27 100644 --- a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts @@ -86,12 +86,12 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR }, envVariables); } - public resolveWithInteractionReplace(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary): Promise { - // resolve any non-interactive variables - config = this.resolveAny(folder, config); + public async resolveWithInteractionReplace(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary): Promise { + // resolve any non-interactive variables and any contributed variables + config = await this.resolveAny(folder, config); // resolve input variables in the order in which they are encountered - return this.resolveWithInteraction(folder, config, section, variables).then(mapping => { + return this.resolveWithInteraction(folder, config, section, variables, true).then(mapping => { // finally substitute evaluated command variables (if there are any) if (!mapping) { return null; @@ -103,9 +103,9 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR }); } - public resolveWithInteraction(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary): Promise | undefined> { - // resolve any non-interactive variables - const resolved = this.resolveAnyMap(folder, config); + public async resolveWithInteraction(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary, skipContributed: boolean = false): Promise | undefined> { + // resolve any non-interactive variables and any contributed variables + const resolved = await this.resolveAnyMap(folder, config); config = resolved.newConfig; const allVariableMapping: Map = resolved.resolvedVariables; diff --git a/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts index 88baea5936..7994a2bdff 100644 --- a/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts @@ -10,7 +10,7 @@ import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; export const IConfigurationResolverService = createDecorator('configurationResolverService'); export interface IConfigurationResolverService { - _serviceBrand: any; + _serviceBrand: undefined; resolve(folder: IWorkspaceFolder | undefined, value: string): string; resolve(folder: IWorkspaceFolder | undefined, value: string[]): string[]; @@ -20,7 +20,7 @@ export interface IConfigurationResolverService { * Recursively resolves all variables in the given config and returns a copy of it with substituted values. * Command variables are only substituted if a "commandValueMapping" dictionary is given and if it contains an entry for the command. */ - resolveAny(folder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): any; + resolveAny(folder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise; /** * Recursively resolves all variables (including commands and user input) in the given config and returns a copy of it with substituted values. @@ -36,6 +36,12 @@ export interface IConfigurationResolverService { * Keys in the map will be of the format input:variableName or command:variableName. */ resolveWithInteraction(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary): Promise | undefined>; + + /** + * Contributes a variable that can be resolved later. Consumers that use resolveAny, resolveWithInteraction, + * and resolveWithInteractionReplace will have contributed variables resolved. + */ + contributeVariable(variable: string, resolution: () => Promise): void; } export interface PromptStringInputInfo { diff --git a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts index 7700987a66..fa914ed8e3 100644 --- a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts @@ -28,8 +28,11 @@ export interface IVariableResolveContext { export class AbstractVariableResolverService implements IConfigurationResolverService { static VARIABLE_REGEXP = /\$\{(.*?)\}/g; + static VARIABLE_REGEXP_SINGLE = /\$\{(.*?)\}/; - _serviceBrand: any; + _serviceBrand: undefined; + + private _contributedVariables: Map Promise> = new Map(); constructor( private _context: IVariableResolveContext, @@ -50,8 +53,7 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe return this.recursiveResolve(root ? root.uri : undefined, value); } - public resolveAnyBase(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary, resolvedVariables?: Map): any { - + private async resolveAnyBase(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary, resolvedVariables?: Map): Promise { const result = objects.deepClone(config) as any; // hoist platform specific attributes to top level @@ -69,16 +71,16 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe delete result.linux; // substitute all variables recursively in string values - return this.recursiveResolve(workspaceFolder ? workspaceFolder.uri : undefined, result, commandValueMapping, resolvedVariables); + return this.recursiveResolvePromise(workspaceFolder ? workspaceFolder.uri : undefined, result, commandValueMapping, resolvedVariables); } - public resolveAny(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): any { + public resolveAny(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise { return this.resolveAnyBase(workspaceFolder, config, commandValueMapping); } - public resolveAnyMap(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): { newConfig: any, resolvedVariables: Map } { + protected async resolveAnyMap(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise<{ newConfig: any, resolvedVariables: Map }> { const resolvedVariables = new Map(); - const newConfig = this.resolveAnyBase(workspaceFolder, config, commandValueMapping, resolvedVariables); + const newConfig = await this.resolveAnyBase(workspaceFolder, config, commandValueMapping, resolvedVariables); return { newConfig, resolvedVariables }; } @@ -90,6 +92,14 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe throw new Error('resolveWithInteraction not implemented.'); } + public contributeVariable(variable: string, resolution: () => Promise): void { + if (this._contributedVariables.has(variable)) { + throw new Error('Variable ' + variable + ' is contributed twice.'); + } else { + this._contributedVariables.set(variable, resolution); + } + } + private recursiveResolve(folderUri: uri | undefined, value: any, commandValueMapping?: IStringDictionary, resolvedVariables?: Map): any { if (types.isString(value)) { return this.resolveString(folderUri, value, commandValueMapping, resolvedVariables); @@ -106,6 +116,23 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe return value; } + private async recursiveResolvePromise(folderUri: uri | undefined, value: any, commandValueMapping?: IStringDictionary, resolvedVariables?: Map): Promise { + if (types.isString(value)) { + return this.resolveStringPromise(folderUri, value, commandValueMapping, resolvedVariables); + } else if (types.isArray(value)) { + return Promise.all(value.map(s => this.recursiveResolvePromise(folderUri, s, commandValueMapping, resolvedVariables))); + } else if (types.isObject(value)) { + let result: IStringDictionary | string[]> = Object.create(null); + const keys = Object.keys(value); + for (let key of keys) { + const replaced = await this.resolveStringPromise(folderUri, key, commandValueMapping, resolvedVariables); + result[replaced] = await this.recursiveResolvePromise(folderUri, value[key], commandValueMapping, resolvedVariables); + } + return result; + } + return value; + } + private resolveString(folderUri: uri | undefined, value: string, commandValueMapping: IStringDictionary | undefined, resolvedVariables?: Map): string { // loop through all variables occurrences in 'value' @@ -123,6 +150,37 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe return replaced; } + private async resolveStringPromise(folderUri: uri | undefined, value: string, commandValueMapping: IStringDictionary | undefined, resolvedVariables?: Map): Promise { + // loop through all variables occurrences in 'value' + const matches = value.match(AbstractVariableResolverService.VARIABLE_REGEXP); + const replaces: Map = new Map(); + if (!matches) { + return value; + } + for (const match of matches) { + const evaluate = await this.evaluateSingleContributedVariable(match, match.match(AbstractVariableResolverService.VARIABLE_REGEXP_SINGLE)![1]); + if (evaluate !== match) { + replaces.set(match, evaluate); + } + } + + const replaced = value.replace(AbstractVariableResolverService.VARIABLE_REGEXP, (match: string, variable: string) => { + + let resolvedValue = this.evaluateSingleVariable(match, variable, folderUri, commandValueMapping); + if ((resolvedValue === match) && (replaces.has(match))) { + resolvedValue = replaces.get(match)!; + } + + if (resolvedVariables) { + resolvedVariables.set(variable, resolvedValue); + } + + return resolvedValue; + }); + + return replaced; + } + private evaluateSingleVariable(match: string, variable: string, folderUri: uri | undefined, commandValueMapping: IStringDictionary | undefined): string { // try to separate variable arguments from variable name @@ -271,6 +329,16 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe } } + private async evaluateSingleContributedVariable(match: string, variable: string): Promise { + if (this._contributedVariables.has(variable)) { + const contributedValue: string | undefined = await this._contributedVariables.get(variable)!(); + if (contributedValue !== undefined) { + return contributedValue; + } + } + return match; + } + private resolveFromMap(match: string, argument: string | undefined, commandValueMapping: IStringDictionary | undefined, prefix: string): string { if (argument && commandValueMapping) { const v = commandValueMapping[prefix + ':' + argument]; 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 e2f5d65c7a..7701bc5292 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 @@ -487,11 +487,24 @@ suite('Configuration Resolver Service', () => { assert.equal(2, mockCommandService.callCount); }); }); + test('contributed variable', () => { + const buildTask = 'npm: compile'; + const variable = 'defaultBuildTask'; + const configuration = { + 'name': '${' + variable + '}', + }; + configurationResolverService!.contributeVariable(variable, async () => { return buildTask; }); + return configurationResolverService!.resolveAny(workspace, configuration).then(result => { + assert.deepEqual(result, { + 'name': `${buildTask}` + }); + }); + }); }); class MockConfigurationService implements IConfigurationService { - public _serviceBrand: any; + public _serviceBrand: undefined; public serviceId = IConfigurationService; public constructor(private configuration: any = {}) { } public inspect(key: string, overrides?: IConfigurationOverrides): any { return { value: getConfigurationValue(this.getValue(), key), default: getConfigurationValue(this.getValue(), key), user: getConfigurationValue(this.getValue(), key), workspaceFolder: undefined, folder: undefined }; } @@ -518,7 +531,7 @@ class MockConfigurationService implements IConfigurationService { class MockCommandService implements ICommandService { - public _serviceBrand: any; + public _serviceBrand: undefined; public callCount = 0; onWillExecuteCommand = () => Disposable.None; @@ -538,7 +551,7 @@ class MockCommandService implements ICommandService { } class MockQuickInputService implements IQuickInputService { - _serviceBrand: any; + _serviceBrand: undefined; public pick(picks: Promise[]> | QuickPickInput[], options?: IPickOptions & { canPickMany: true }, token?: CancellationToken): Promise; public pick(picks: Promise[]> | QuickPickInput[], options?: IPickOptions & { canPickMany: false }, token?: CancellationToken): Promise; diff --git a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts index f6a0172da7..f00b8f6c79 100644 --- a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts @@ -28,7 +28,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class ContextMenuService extends Disposable implements IContextMenuService { - _serviceBrand: any; + _serviceBrand: undefined; get onDidContextMenu(): Event { return this.impl.onDidContextMenu; } @@ -63,7 +63,7 @@ export class ContextMenuService extends Disposable implements IContextMenuServic class NativeContextMenuService extends Disposable implements IContextMenuService { - _serviceBrand: any; + _serviceBrand: undefined; private _onDidContextMenu = this._register(new Emitter()); readonly onDidContextMenu: Event = this._onDidContextMenu.event; diff --git a/src/vs/workbench/services/credentials/browser/credentialsService.ts b/src/vs/workbench/services/credentials/browser/credentialsService.ts index 62feab39ae..30db14a5ea 100644 --- a/src/vs/workbench/services/credentials/browser/credentialsService.ts +++ b/src/vs/workbench/services/credentials/browser/credentialsService.ts @@ -5,7 +5,6 @@ import { ICredentialsService } from 'vs/workbench/services/credentials/common/credentials'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; export interface ICredentialsProvider { @@ -13,11 +12,12 @@ export interface ICredentialsProvider { setPassword(service: string, account: string, password: string): Promise; deletePassword(service: string, account: string): Promise; findPassword(service: string): Promise; + findCredentials(service: string): Promise>; } export class BrowserCredentialsService implements ICredentialsService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private credentialsProvider: ICredentialsProvider; @@ -25,25 +25,29 @@ export class BrowserCredentialsService implements ICredentialsService { if (environmentService.options && environmentService.options.credentialsProvider) { this.credentialsProvider = environmentService.options.credentialsProvider; } else { - this.credentialsProvider = new LocalStorageCredentialsProvider(); + this.credentialsProvider = new InMemoryCredentialsProvider(); } } - async getPassword(service: string, account: string): Promise { + getPassword(service: string, account: string): Promise { return this.credentialsProvider.getPassword(service, account); } - async setPassword(service: string, account: string, password: string): Promise { + setPassword(service: string, account: string, password: string): Promise { return this.credentialsProvider.setPassword(service, account, password); } - async deletePassword(service: string, account: string): Promise { + deletePassword(service: string, account: string): Promise { return this.credentialsProvider.deletePassword(service, account); } - async findPassword(service: string): Promise { + findPassword(service: string): Promise { return this.credentialsProvider.findPassword(service); } + + findCredentials(service: string): Promise> { + return this.credentialsProvider.findCredentials(service); + } } interface ICredential { @@ -52,80 +56,50 @@ interface ICredential { password: string; } -class LocalStorageCredentialsProvider implements ICredentialsProvider { +class InMemoryCredentialsProvider implements ICredentialsProvider { - static readonly CREDENTIALS_OPENED_KEY = 'credentials.provider'; - - private _credentials: ICredential[]; - private get credentials(): ICredential[] { - if (!this._credentials) { - try { - const serializedCredentials = window.localStorage.getItem(LocalStorageCredentialsProvider.CREDENTIALS_OPENED_KEY); - if (serializedCredentials) { - this._credentials = JSON.parse(serializedCredentials); - } - } catch (error) { - // ignore - } - - if (!Array.isArray(this._credentials)) { - this._credentials = []; - } - } - - return this._credentials; - } - - private save(): void { - window.localStorage.setItem(LocalStorageCredentialsProvider.CREDENTIALS_OPENED_KEY, JSON.stringify(this.credentials)); - } + private credentials: ICredential[] = []; async getPassword(service: string, account: string): Promise { - return this.doGetPassword(service, account); + const credential = this.doFindPassword(service, account); + + return credential ? credential.password : null; } - private async doGetPassword(service: string, account?: string): Promise { + async setPassword(service: string, account: string, password: string): Promise { + this.deletePassword(service, account); + this.credentials.push({ service, account, password }); + } + + async deletePassword(service: string, account: string): Promise { + const credential = this.doFindPassword(service, account); + if (credential) { + this.credentials = this.credentials.splice(this.credentials.indexOf(credential), 1); + } + + return !!credential; + } + + async findPassword(service: string): Promise { + const credential = this.doFindPassword(service); + + return credential ? credential.password : null; + } + + private doFindPassword(service: string, account?: string): ICredential | null { for (const credential of this.credentials) { - if (credential.service === service) { - if (typeof account !== 'string' || account === credential.account) { - return credential.password; - } + if (credential.service === service && (typeof account !== 'string' || credential.account === account)) { + return credential; } } return null; } - async setPassword(service: string, account: string, password: string): Promise { - this.deletePassword(service, account); - - this.credentials.push({ service, account, password }); - - this.save(); - } - - async deletePassword(service: string, account: string): Promise { - let found = false; - - this._credentials = this.credentials.filter(credential => { - if (credential.service === service && credential.account === account) { - found = true; - - return false; - } - - return true; - }); - - if (found) { - this.save(); - } - - return found; - } - - async findPassword(service: string): Promise { - return this.doGetPassword(service); + async findCredentials(service: string): Promise> { + return this.credentials + .filter(credential => credential.service === service) + .map(({ account, password }) => ({ account, password })); } } diff --git a/src/vs/workbench/services/credentials/common/credentials.ts b/src/vs/workbench/services/credentials/common/credentials.ts index 49c19b880b..f8f4dedc95 100644 --- a/src/vs/workbench/services/credentials/common/credentials.ts +++ b/src/vs/workbench/services/credentials/common/credentials.ts @@ -3,16 +3,17 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export const ICredentialsService = createDecorator('ICredentialsService'); export interface ICredentialsService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; getPassword(service: string, account: string): Promise; setPassword(service: string, account: string, password: string): Promise; deletePassword(service: string, account: string): Promise; findPassword(service: string): Promise; + findCredentials(service: string): Promise>; } diff --git a/src/vs/workbench/services/credentials/node/credentialsService.ts b/src/vs/workbench/services/credentials/node/credentialsService.ts index d3b203c3ce..d6c20bdf9a 100644 --- a/src/vs/workbench/services/credentials/node/credentialsService.ts +++ b/src/vs/workbench/services/credentials/node/credentialsService.ts @@ -6,18 +6,11 @@ import { ICredentialsService } from 'vs/workbench/services/credentials/common/credentials'; import { IdleValue } from 'vs/base/common/async'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; - -type KeytarModule = { - getPassword(service: string, account: string): Promise; - setPassword(service: string, account: string, password: string): Promise; - deletePassword(service: string, account: string): Promise; - findPassword(service: string): Promise; -}; +type KeytarModule = typeof import('keytar'); export class KeytarCredentialsService implements ICredentialsService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private readonly _keytar = new IdleValue>(() => import('keytar')); @@ -40,6 +33,11 @@ export class KeytarCredentialsService implements ICredentialsService { const keytar = await this._keytar.getValue(); return keytar.findPassword(service); } + + async findCredentials(service: string): Promise> { + const keytar = await this._keytar.getValue(); + return keytar.findCredentials(service); + } } registerSingleton(ICredentialsService, KeytarCredentialsService, true); diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index b2cd1a2153..5d797e91fd 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -18,14 +18,12 @@ export interface IDecorationData { readonly letter?: string; readonly tooltip?: string; readonly bubble?: boolean; - readonly source?: string; } export interface IDecoration { readonly tooltip: string; readonly labelClassName: string; readonly badgeClassName: string; - update(data: IDecorationData): IDecoration; } export interface IDecorationsProvider { @@ -40,11 +38,11 @@ export interface IResourceDecorationChangeEvent { export interface IDecorationsService { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; readonly onDidChangeDecorations: Event; registerDecorationsProvider(provider: IDecorationsProvider): IDisposable; - getDecoration(uri: URI, includeChildren: boolean, overwrite?: IDecorationData): IDecoration | undefined; + getDecoration(uri: URI, includeChildren: boolean): IDecoration | undefined; } diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index c3c233a680..eda895a96f 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -144,17 +144,7 @@ class DecorationStyles extends Disposable { return { labelClassName, badgeClassName, - tooltip, - update: (replace) => { - let newData = data.slice(); - for (let i = 0; i < newData.length; i++) { - if (newData[i].source === replace.source) { - // replace - newData[i] = replace; - } - } - return this.asDecoration(newData, onlyChildren); - } + tooltip }; } @@ -336,7 +326,7 @@ class DecorationProviderWrapper { export class FileDecorationsService implements IDecorationsService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _data = new LinkedList(); private readonly _onDidChangeDecorationsDelayed = new Emitter(); @@ -402,7 +392,7 @@ export class FileDecorationsService implements IDecorationsService { }); } - getDecoration(uri: URI, includeChildren: boolean, overwrite?: IDecorationData): IDecoration | undefined { + getDecoration(uri: URI, includeChildren: boolean): IDecoration | undefined { let data: IDecorationData[] = []; let containsChildren: boolean = false; for (let iter = this._data.iterator(), next = iter.next(); !next.done; next = iter.next()) { @@ -414,22 +404,9 @@ export class FileDecorationsService implements IDecorationsService { }); } - if (data.length === 0) { - // nothing, maybe overwrite data - if (overwrite) { - return this._decorationStyles.asDecoration([overwrite], containsChildren); - } else { - return undefined; - } - } else { - // result, maybe overwrite - let result = this._decorationStyles.asDecoration(data, containsChildren); - if (overwrite) { - return result.update(overwrite); - } else { - return result; - } - } + return data.length === 0 + ? undefined + : this._decorationStyles.asDecoration(data, containsChildren); } } function getColor(theme: ITheme, color: string | undefined) { @@ -442,4 +419,4 @@ function getColor(theme: ITheme, color: string | undefined) { return 'inherit'; } -registerSingleton(IDecorationsService, FileDecorationsService); \ No newline at end of file +registerSingleton(IDecorationsService, FileDecorationsService); diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index 02f9b0f878..9f601f9e18 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -146,32 +146,6 @@ suite('DecorationsService', function () { assert.equal(typeof deco.tooltip, 'string'); }); - test('Overwrite data', function () { - - let someUri = URI.parse('file:///some/path/some/file.txt'); - let deco = service.getDecoration(someUri, false); - assert.equal(deco, undefined); - - deco = service.getDecoration(someUri, false, { tooltip: 'Overwrite' })!; - assert.equal(deco.tooltip, 'Overwrite'); - - let reg = service.registerDecorationsProvider({ - label: 'Test', - onDidChange: Event.None, - provideDecorations(uri: URI) { - return { tooltip: 'FromMe', source: 'foo' }; - } - }); - - deco = service.getDecoration(someUri, false)!; - assert.equal(deco.tooltip, 'FromMe'); - - deco = service.getDecoration(someUri, false, { source: 'foo', tooltip: 'O' })!; - assert.equal(deco.tooltip, 'O'); - - reg.dispose(); - }); - test('Decorations not showing up for second root folder #48502', async function () { let cancelCount = 0; diff --git a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts index 96dd9986f1..1e566b2f47 100644 --- a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts @@ -20,10 +20,11 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { isWeb } from 'vs/base/common/platform'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; export class FileDialogService implements IFileDialogService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @IWindowService private readonly windowService: IWindowService, @@ -32,7 +33,8 @@ export class FileDialogService implements IFileDialogService { @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IInstantiationService private readonly instantiationService: IInstantiationService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IFileService private readonly fileService: IFileService + @IFileService private readonly fileService: IFileService, + @IOpenerService private readonly openerService: IOpenerService ) { } defaultFilePath(schemeFilter = this.getSchemeFilterForWindow()): URI | undefined { @@ -85,10 +87,10 @@ export class FileDialogService implements IFileDialogService { }; } - private shouldUseSimplified(schema: string): boolean { - const setting = this.configurationService.getValue('files.simpleDialog.enable'); + private shouldUseSimplified(schema: string): { useSimplified: boolean, isSetting: boolean } { + const setting = (this.configurationService.getValue('files.simpleDialog.enable') === true); - return (schema !== Schemas.file) || (setting === true); + return { useSimplified: (schema !== Schemas.file) || setting, isSetting: (schema === Schemas.file) && setting }; } private addFileSchemaIfNeeded(schema: string): string[] { @@ -108,7 +110,8 @@ export class FileDialogService implements IFileDialogService { options.defaultUri = this.defaultFilePath(schema); } - if (this.shouldUseSimplified(schema)) { + const shouldUseSimplified = this.shouldUseSimplified(schema); + if (shouldUseSimplified.useSimplified) { const title = nls.localize('openFileOrFolder.title', 'Open File Or Folder'); const availableFileSystems = this.addFileSchemaIfNeeded(schema); @@ -118,7 +121,11 @@ export class FileDialogService implements IFileDialogService { const stat = await this.fileService.resolve(uri); const toOpen: IURIToOpen = stat.isDirectory ? { folderUri: uri } : { fileUri: uri }; - return this.windowService.openWindow([toOpen], { forceNewWindow: options.forceNewWindow }); + if (stat.isDirectory || options.forceNewWindow || shouldUseSimplified.isSetting) { + return this.windowService.openWindow([toOpen], { forceNewWindow: options.forceNewWindow }); + } else { + return this.openerService.open(uri); + } } return; @@ -134,13 +141,18 @@ export class FileDialogService implements IFileDialogService { options.defaultUri = this.defaultFilePath(schema); } - if (this.shouldUseSimplified(schema)) { + const shouldUseSimplified = this.shouldUseSimplified(schema); + if (shouldUseSimplified.useSimplified) { const title = nls.localize('openFile.title', 'Open File'); const availableFileSystems = this.addFileSchemaIfNeeded(schema); const uri = await this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }); if (uri) { - return this.windowService.openWindow([{ fileUri: uri }], { forceNewWindow: options.forceNewWindow }); + if (options.forceNewWindow || shouldUseSimplified.isSetting) { + return this.windowService.openWindow([{ fileUri: uri }], { forceNewWindow: options.forceNewWindow }); + } else { + return this.openerService.open(uri); + } } return; @@ -156,7 +168,7 @@ export class FileDialogService implements IFileDialogService { options.defaultUri = this.defaultFolderPath(schema); } - if (this.shouldUseSimplified(schema)) { + if (this.shouldUseSimplified(schema).useSimplified) { const title = nls.localize('openFolder.title', 'Open Folder'); const availableFileSystems = this.addFileSchemaIfNeeded(schema); @@ -178,7 +190,7 @@ export class FileDialogService implements IFileDialogService { options.defaultUri = this.defaultWorkspacePath(schema); } - if (this.shouldUseSimplified(schema)) { + if (this.shouldUseSimplified(schema).useSimplified) { const title = nls.localize('openWorkspace.title', 'Open Workspace'); const filters: FileFilter[] = [{ name: nls.localize('filterName.workspace', 'Workspace'), extensions: [WORKSPACE_EXTENSION] }]; const availableFileSystems = this.addFileSchemaIfNeeded(schema); @@ -196,7 +208,7 @@ export class FileDialogService implements IFileDialogService { async pickFileToSave(options: ISaveDialogOptions): Promise { const schema = this.getFileSystemSchema(options); - if (this.shouldUseSimplified(schema)) { + if (this.shouldUseSimplified(schema).useSimplified) { if (!options.availableFileSystems) { options.availableFileSystems = this.addFileSchemaIfNeeded(schema); } @@ -225,7 +237,7 @@ export class FileDialogService implements IFileDialogService { async showSaveDialog(options: ISaveDialogOptions): Promise { const schema = this.getFileSystemSchema(options); - if (this.shouldUseSimplified(schema)) { + if (this.shouldUseSimplified(schema).useSimplified) { if (!options.availableFileSystems) { options.availableFileSystems = this.addFileSchemaIfNeeded(schema); } @@ -243,7 +255,7 @@ export class FileDialogService implements IFileDialogService { async showOpenDialog(options: IOpenDialogOptions): Promise { const schema = this.getFileSystemSchema(options); - if (this.shouldUseSimplified(schema)) { + if (this.shouldUseSimplified(schema).useSimplified) { if (!options.availableFileSystems) { options.availableFileSystems = this.addFileSchemaIfNeeded(schema); } diff --git a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts index 60fb9e2d1a..fb56e8531d 100644 --- a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts +++ b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts @@ -101,7 +101,7 @@ export class RemoteFileDialog { } public async showOpenDialog(options: IOpenDialogOptions = {}): Promise { - this.scheme = this.getScheme(options.availableFileSystems); + this.scheme = this.getScheme(options.availableFileSystems, options.defaultUri); this.userHome = await this.getUserHome(); const newOptions = await this.getOptions(options); if (!newOptions) { @@ -112,7 +112,7 @@ export class RemoteFileDialog { } public async showSaveDialog(options: ISaveDialogOptions): Promise { - this.scheme = this.getScheme(options.availableFileSystems); + this.scheme = this.getScheme(options.availableFileSystems, options.defaultUri); this.userHome = await this.getUserHome(); this.requiresTrailing = true; const newOptions = await this.getOptions(options, true); @@ -157,8 +157,14 @@ export class RemoteFileDialog { return resources.toLocalResource(URI.from({ scheme: this.scheme, path }), this.scheme === Schemas.file ? undefined : this.remoteAuthority); } - private getScheme(available: string[] | undefined): string { - return available ? available[0] : Schemas.file; + private getScheme(available: string[] | undefined, defaultUri: URI | undefined): string { + if (available) { + if (defaultUri && (available.indexOf(defaultUri.scheme) >= 0)) { + return defaultUri.scheme; + } + return available[0]; + } + return Schemas.file; } private async getRemoteAgentEnvironment(): Promise { @@ -215,7 +221,7 @@ export class RemoteFileDialog { this.filePickBox.autoFocusOnList = false; this.filePickBox.ignoreFocusOut = true; this.filePickBox.ok = true; - if (this.options && this.options.availableFileSystems && (this.options.availableFileSystems.length > 1) && (this.options.availableFileSystems.indexOf(Schemas.file) > -1)) { + if ((this.scheme !== Schemas.file) && this.options && this.options.availableFileSystems && (this.options.availableFileSystems.length > 1) && (this.options.availableFileSystems.indexOf(Schemas.file) > -1)) { this.filePickBox.customButton = true; this.filePickBox.customLabel = nls.localize('remoteFileDialog.local', 'Show Local'); let action; diff --git a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts index 0b70ea812b..0f34cfaaa1 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts @@ -9,7 +9,7 @@ import Severity from 'vs/base/common/severity'; import { isLinux, isWindows } from 'vs/base/common/platform'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; -import { IDialogService, IConfirmation, IConfirmationResult, IDialogOptions } from 'vs/platform/dialogs/common/dialogs'; +import { IDialogService, IConfirmation, IConfirmationResult, IDialogOptions, IShowResult } from 'vs/platform/dialogs/common/dialogs'; import { DialogService as HTMLDialogService } from 'vs/platform/dialogs/browser/dialogService'; import { ILogService } from 'vs/platform/log/common/log'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -36,7 +36,7 @@ interface IMassagedMessageBoxOptions { } export class DialogService implements IDialogService { - _serviceBrand: any; + _serviceBrand: undefined; private impl: IDialogService; @@ -63,14 +63,14 @@ export class DialogService implements IDialogService { confirm(confirmation: IConfirmation): Promise { return this.impl.confirm(confirmation); } - show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions | undefined): Promise { + show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions | undefined): Promise { return this.impl.show(severity, message, buttons, options); } } class NativeDialogService implements IDialogService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @IWindowService private readonly windowService: IWindowService, @@ -129,7 +129,7 @@ class NativeDialogService implements IDialogService { return opts; } - async show(severity: Severity, message: string, buttons: string[], dialogOptions?: IDialogOptions): Promise { + async show(severity: Severity, message: string, buttons: string[], dialogOptions?: IDialogOptions): Promise { this.logService.trace('DialogService#show', message); const { options, buttonIndexMap } = this.massageMessageBoxOptions({ @@ -137,11 +137,13 @@ class NativeDialogService implements IDialogService { buttons, type: (severity === Severity.Info) ? 'question' : (severity === Severity.Error) ? 'error' : (severity === Severity.Warning) ? 'warning' : 'none', cancelId: dialogOptions ? dialogOptions.cancelId : undefined, - detail: dialogOptions ? dialogOptions.detail : undefined + detail: dialogOptions ? dialogOptions.detail : undefined, + checkboxLabel: dialogOptions && dialogOptions.checkbox ? dialogOptions.checkbox.label : undefined, + checkboxChecked: dialogOptions && dialogOptions.checkbox ? dialogOptions.checkbox.checked : undefined }); const result = await this.windowService.showMessageBox(options); - return buttonIndexMap[result.button]; + return { choice: buttonIndexMap[result.button], checkboxChecked: result.checkboxChecked }; } private massageMessageBoxOptions(options: Electron.MessageBoxOptions): IMassagedMessageBoxOptions { diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 01af47686b..93cdd0bcd3 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IInstantiationService, ServicesAccessor, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IResourceInput, ITextEditorOptions, IEditorOptions, EditorActivation } from 'vs/platform/editor/common/editor'; import { IEditorInput, IEditor, GroupIdentifier, IFileEditorInput, IUntitledResourceInput, IResourceDiffInput, IResourceSideBySideInput, IEditorInputFactoryRegistry, Extensions as EditorExtensions, IFileInputFactory, EditorInput, SideBySideEditorInput, IEditorInputWithOptions, isEditorInputWithOptions, EditorOptions, TextEditorOptions, IEditorIdentifier, IEditorCloseEvent, ITextEditor, ITextDiffEditor, ITextSideBySideEditor, toResource, SideBySideEditor } from 'vs/workbench/common/editor'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; @@ -35,7 +35,7 @@ type OpenInEditorGroup = IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTI export class EditorService extends Disposable implements EditorServiceImpl { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private static CACHE: ResourceMap = new ResourceMap(); @@ -147,6 +147,10 @@ export class EditorService extends Disposable implements EditorServiceImpl { } private onGroupWillOpenEditor(group: IEditorGroup, event: IEditorOpeningEvent): void { + if (event.options && event.options.ignoreOverrides) { + return; + } + for (const handler of this.openEditorHandlers) { const result = handler(event.editor, event.options, group); if (result && result.override) { @@ -641,10 +645,10 @@ export class EditorService extends Disposable implements EditorServiceImpl { return input; } - private toDiffLabel(input: EditorInput): string | null { + private toDiffLabel(input: EditorInput): string | undefined { const res = input.getResource(); if (!res) { - return null; + return undefined; } // Do not try to extract any paths from simple untitled editors diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index 5c6f95e1f2..0c7a55a61e 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; -import { createDecorator, ServiceIdentifier, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IEditorInput, IEditor, GroupIdentifier, IEditorInputWithOptions, CloseDirection, IEditorPartOptions } from 'vs/workbench/common/editor'; import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -149,7 +149,7 @@ export const enum EditorsOrder { export interface IEditorGroupsService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; /** * An event for when the active editor group changes. The active editor diff --git a/src/vs/workbench/services/editor/common/editorService.ts b/src/vs/workbench/services/editor/common/editorService.ts index 0a2c4d6af6..3d49efcd32 100644 --- a/src/vs/workbench/services/editor/common/editorService.ts +++ b/src/vs/workbench/services/editor/common/editorService.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, ServiceIdentifier, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IResourceInput, IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { IEditorInput, IEditor, GroupIdentifier, IEditorInputWithOptions, IUntitledResourceInput, IResourceDiffInput, IResourceSideBySideInput, ITextEditor, ITextDiffEditor, ITextSideBySideEditor } from 'vs/workbench/common/editor'; import { Event } from 'vs/base/common/event'; @@ -46,7 +46,7 @@ export interface IVisibleEditor extends IEditor { export interface IEditorService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; /** * Emitted when the currently active editor changes. diff --git a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts index 16999786f5..50462ce3fa 100644 --- a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts @@ -24,7 +24,7 @@ export class TestEditorControl extends BaseEditor { constructor(@ITelemetryService telemetryService: ITelemetryService) { super('MyFileEditorForEditorGroupService', NullTelemetryService, new TestThemeService(), new TestStorageService()); } - async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { + async setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { super.setInput(input, options, token); await input.resolve(); diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index 5abeb6a07f..e0cfa7b6cb 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { IEditorModel } from 'vs/platform/editor/common/editor'; +import { IEditorModel, EditorActivation } from 'vs/platform/editor/common/editor'; import { URI } from 'vs/base/common/uri'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { EditorInput, EditorOptions, IFileEditorInput, IEditorInput } from 'vs/workbench/common/editor'; @@ -12,7 +12,7 @@ import { workbenchInstantiationService, TestStorageService } from 'vs/workbench/ import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; import { EditorService, DelegatingEditorService } from 'vs/workbench/services/editor/browser/editorService'; -import { IEditorGroup, IEditorGroupsService, GroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { IEditorGroup, IEditorGroupsService, GroupDirection, GroupsArrangement } from 'vs/workbench/services/editor/common/editorGroupsService'; import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; @@ -37,7 +37,7 @@ export class TestEditorControl extends BaseEditor { constructor(@ITelemetryService telemetryService: ITelemetryService) { super('MyTestEditorForEditorService', NullTelemetryService, new TestThemeService(), new TestStorageService()); } - async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { + async setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { super.setInput(input, options, token); await input.resolve(); @@ -408,6 +408,47 @@ suite.skip('EditorService', () => { // {{SQL CARBON EDIT}} skip suite assert.equal(editor!.group, part.groups[1]); }); + test('editor group activation', async () => { + const partInstantiator = workbenchInstantiationService(); + + const part = partInstantiator.createInstance(EditorPart); + part.create(document.createElement('div')); + part.layout(400, 300); + + const testInstantiationService = partInstantiator.createChild(new ServiceCollection([IEditorGroupsService, part])); + + const service: IEditorService = testInstantiationService.createInstance(EditorService); + + const input1 = testInstantiationService.createInstance(TestEditorInput, URI.parse('my://resource1-openside')); + const input2 = testInstantiationService.createInstance(TestEditorInput, URI.parse('my://resource2-openside')); + + const rootGroup = part.activeGroup; + + await part.whenRestored; + + await service.openEditor(input1, { pinned: true }, rootGroup); + let editor = await service.openEditor(input2, { pinned: true, preserveFocus: true, activation: EditorActivation.ACTIVATE }, SIDE_GROUP); + const sideGroup = editor!.group; + + assert.equal(part.activeGroup, sideGroup); + + editor = await service.openEditor(input1, { pinned: true, preserveFocus: true, activation: EditorActivation.PRESERVE }, rootGroup); + assert.equal(part.activeGroup, sideGroup); + + editor = await service.openEditor(input1, { pinned: true, preserveFocus: true, activation: EditorActivation.ACTIVATE }, rootGroup); + assert.equal(part.activeGroup, rootGroup); + + editor = await service.openEditor(input2, { pinned: true, activation: EditorActivation.PRESERVE }, sideGroup); + assert.equal(part.activeGroup, rootGroup); + + editor = await service.openEditor(input2, { pinned: true, activation: EditorActivation.ACTIVATE }, sideGroup); + assert.equal(part.activeGroup, sideGroup); + + part.arrangeGroups(GroupsArrangement.MINIMIZE_OTHERS); + editor = await service.openEditor(input1, { pinned: true, preserveFocus: true, activation: EditorActivation.RESTORE }, rootGroup); + assert.equal(part.activeGroup, sideGroup); + }); + test('active editor change / visible editor change events', async function () { const partInstantiator = workbenchInstantiationService(); diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index fc8b9784c5..f706be9631 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -5,7 +5,6 @@ import { IWindowConfiguration, IPath, IPathsToWaitFor } from 'vs/platform/windows/common/windows'; import { IExtensionHostDebugParams, IDebugParams, BACKUPS } from 'vs/platform/environment/common/environment'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; @@ -69,7 +68,7 @@ interface IBrowserWorkbenchEnvironemntConstructionOptions extends IWorkbenchCons export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironmentService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; readonly configuration: IWindowConfiguration = new BrowserWindowConfiguration(); diff --git a/src/vs/workbench/services/environment/common/environmentService.ts b/src/vs/workbench/services/environment/common/environmentService.ts index 3a1d98dbf5..4682637295 100644 --- a/src/vs/workbench/services/environment/common/environmentService.ts +++ b/src/vs/workbench/services/environment/common/environmentService.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { IEnvironmentService, IDebugParams } from 'vs/platform/environment/common/environment'; import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api'; @@ -13,7 +13,7 @@ export const IWorkbenchEnvironmentService = createDecorator; + _serviceBrand: undefined; readonly configuration: IWindowConfiguration; diff --git a/src/vs/workbench/services/environment/node/environmentService.ts b/src/vs/workbench/services/environment/node/environmentService.ts index 22e80a0b3b..e59ba5d06b 100644 --- a/src/vs/workbench/services/environment/node/environmentService.ts +++ b/src/vs/workbench/services/environment/node/environmentService.ts @@ -10,13 +10,12 @@ import { memoize } from 'vs/base/common/decorators'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; import { toBackupWorkspaceResource } from 'vs/workbench/services/backup/common/backup'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { join } from 'vs/base/common/path'; import { IDebugParams } from 'vs/platform/environment/common/environment'; export class WorkbenchEnvironmentService extends EnvironmentService implements IWorkbenchEnvironmentService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; readonly webviewResourceRoot = 'vscode-resource:{{resource}}'; readonly webviewCspSource = 'vscode-resource:'; diff --git a/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts index b6e33975db..51afdf2086 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts @@ -24,7 +24,7 @@ const ENABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/enabled'; export class ExtensionEnablementService extends Disposable implements IExtensionEnablementService { - _serviceBrand: any; + _serviceBrand: undefined; private _onEnablementChanged = new Emitter(); public readonly onEnablementChanged: Event = this._onEnablementChanged.event; diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts index d0bc631b1d..fbfdf43277 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts @@ -19,7 +19,7 @@ export interface IExtensionManagementServer { } export interface IExtensionManagementServerService { - _serviceBrand: any; + _serviceBrand: undefined; readonly localExtensionManagementServer: IExtensionManagementServer | null; readonly remoteExtensionManagementServer: IExtensionManagementServer | null; getExtensionManagementServer(location: URI): IExtensionManagementServer | null; @@ -37,7 +37,7 @@ export const enum EnablementState { export const IExtensionEnablementService = createDecorator('extensionEnablementService'); export interface IExtensionEnablementService { - _serviceBrand: any; + _serviceBrand: undefined; readonly allUserExtensionsDisabled: boolean; @@ -97,7 +97,7 @@ export interface IExtensionRecommendation { export const IExtensionTipsService = createDecorator('extensionTipsService'); export interface IExtensionTipsService { - _serviceBrand: any; + _serviceBrand: undefined; getAllRecommendationsWithReason(): { [id: string]: { reasonId: ExtensionRecommendationReason, reasonText: string }; }; getFileBasedRecommendations(): IExtensionRecommendation[]; getOtherRecommendations(): Promise; diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts index 019d4f7b39..fd146bb2ae 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts @@ -15,7 +15,7 @@ import { ILabelService } from 'vs/platform/label/common/label'; export class ExtensionManagementServerService implements IExtensionManagementServerService { - _serviceBrand: any; + _serviceBrand: undefined; readonly localExtensionManagementServer: IExtensionManagementServer | null = null; readonly remoteExtensionManagementServer: IExtensionManagementServer | null = null; diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts index 80f4a79bc5..b905413cdd 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts @@ -22,7 +22,7 @@ import { IDownloadService } from 'vs/platform/download/common/download'; export class ExtensionManagementService extends Disposable implements IExtensionManagementService { - _serviceBrand: any; + _serviceBrand: undefined; readonly onInstallExtension: Event; readonly onDidInstallExtension: Event; diff --git a/src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.ts index 143de0d0b9..3d02ce9ffb 100644 --- a/src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.ts @@ -24,7 +24,7 @@ const localExtensionManagementServerAuthority: string = 'vscode-local'; export class ExtensionManagementServerService implements IExtensionManagementServerService { - _serviceBrand: any; + _serviceBrand: undefined; readonly localExtensionManagementServer: IExtensionManagementServer; readonly remoteExtensionManagementServer: IExtensionManagementServer | null = null; diff --git a/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts b/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts index 9c0212dd9d..23c3dcbcde 100644 --- a/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts @@ -560,7 +560,7 @@ function aMultiExtensionManagementServerService(instantiationService: TestInstan extensionManagementService: instantiationService.get(IExtensionManagementService) }; return { - _serviceBrand: {}, + _serviceBrand: undefined, localExtensionManagementServer, remoteExtensionManagementServer, getExtensionManagementServer: (location: URI) => { diff --git a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts index 781741a056..66b906eb23 100644 --- a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts +++ b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts @@ -51,7 +51,7 @@ export class WebWorkerExtensionHostStarter implements IExtensionHostStarter { const emitter = new Emitter(); const url = getWorkerBootstrapUrl(require.toUrl('../worker/extensionHostWorkerMain.js'), 'WorkerExtensionHost'); - const worker = new Worker(url); + const worker = new Worker(url, { name: 'WorkerExtensionHost' }); worker.onmessage = (event) => { const { data } = event; diff --git a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts index 9ffd299f00..9226810981 100644 --- a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts +++ b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts @@ -30,7 +30,7 @@ const NO_OP_VOID_PROMISE = Promise.resolve(undefined); export abstract class AbstractExtensionService extends Disposable implements IExtensionService { - public _serviceBrand: any; + public _serviceBrand: undefined; protected readonly _onDidRegisterExtensions: Emitter = this._register(new Emitter()); public readonly onDidRegisterExtensions = this._onDidRegisterExtensions.event; @@ -443,7 +443,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx class ProposedApiController { - private readonly enableProposedApiFor: string | string[]; + private readonly enableProposedApiFor: string[]; private readonly enableProposedApiForAll: boolean; private readonly productAllowProposedApi: Set; @@ -451,15 +451,8 @@ class ProposedApiController { @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IProductService productService: IProductService ) { - this.enableProposedApiFor = environmentService.args['enable-proposed-api'] || []; - if (this.enableProposedApiFor.length) { - // Make enabled proposed API be lowercase for case insensitive comparison - if (Array.isArray(this.enableProposedApiFor)) { - this.enableProposedApiFor = this.enableProposedApiFor.map(id => id.toLowerCase()); - } else { - this.enableProposedApiFor = this.enableProposedApiFor.toLowerCase(); - } - } + // Make enabled proposed API be lowercase for case insensitive comparison + this.enableProposedApiFor = (environmentService.args['enable-proposed-api'] || []).map(id => id.toLowerCase()); this.enableProposedApiForAll = !environmentService.isBuilt || (!!environmentService.extensionDevelopmentLocationURI && productService.nameLong !== 'Visual Studio Code') || diff --git a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts b/src/vs/workbench/services/extensions/common/extensionUrlHandler.ts similarity index 91% rename from src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts rename to src/vs/workbench/services/extensions/common/extensionUrlHandler.ts index 49cd0b17e1..d4569143b8 100644 --- a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/common/extensionUrlHandler.ts @@ -28,22 +28,21 @@ 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); } -export const IExtensionUrlHandler = createDecorator('inactiveExtensionUrlHandler'); +export const IExtensionUrlHandler = createDecorator('extensionUrlHandler'); export interface IExtensionUrlHandler { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; registerExtensionHandler(extensionId: ExtensionIdentifier, handler: IURLHandler): void; unregisterExtensionHandler(extensionId: ExtensionIdentifier): void; } /** - * This class handles URLs which are directed towards inactive extensions. + * This class handles URLs which are directed towards extensions. * If a URL is directed towards an inactive extension, it buffers it, * activates the extension and re-opens the URL once the extension registers * a URL handler. If the extension never registers a URL handler, the urls @@ -53,7 +52,7 @@ export interface IExtensionUrlHandler { */ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { - readonly _serviceBrand: any; + readonly _serviceBrand: undefined; private extensionHandlers = new Map(); private uriBuffer = new Map(); @@ -114,11 +113,11 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { } const result = await this.dialogService.confirm({ - message: localize('confirmUrl', "Allow an extension to open this URL?", extensionId), + message: localize('confirmUrl', "Allow an extension to open this URI?", 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}`, + detail: `${extension.displayName || extension.name} (${extensionId}) wants to open a URI:\n\n${uriString}`, primaryButton: localize('open', "&&Open"), type: 'question' }); @@ -128,7 +127,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { } if (result.checkboxChecked) { - this.addConfirmedExtensionIdToStorage(extensionId); + await this.addConfirmedExtensionIdToStorage(extensionId); } } @@ -290,10 +289,8 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { } private getConfirmedExtensionIds(): Set { - const ids = [ - ...this.getConfirmedExtensionIdsFromStorage(), - ...this.getConfirmedExtensionIdsFromConfiguration(), - ].map(extensionId => ExtensionIdentifier.toKey(extensionId)); + const ids = this.getConfirmedExtensionIdsFromConfiguration() + .map(extensionId => ExtensionIdentifier.toKey(extensionId)); return new Set(ids); } @@ -308,26 +305,12 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { return confirmedExtensionIds; } - private getConfirmedExtensionIdsFromStorage(): Array { - const confirmedExtensionIdsJson = this.storageService.get(CONFIRMED_EXTENSIONS_STORAGE_KEY, StorageScope.GLOBAL, '[]'); + private async addConfirmedExtensionIdToStorage(extensionId: string): Promise { + const confirmedExtensionIds = this.configurationService.getValue>(CONFIRMED_EXTENSIONS_CONFIGURATION_KEY); + const set = new Set(confirmedExtensionIds); + set.add(extensionId); - 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, - ); + await this.configurationService.updateValue(CONFIRMED_EXTENSIONS_CONFIGURATION_KEY, [...set.values()]); } dispose(): void { diff --git a/src/vs/workbench/services/extensions/common/extensions.ts b/src/vs/workbench/services/extensions/common/extensions.ts index 515025e22b..719d36a3b5 100644 --- a/src/vs/workbench/services/extensions/common/extensions.ts +++ b/src/vs/workbench/services/extensions/common/extensions.ts @@ -130,7 +130,7 @@ export interface IResponsiveStateChangeEvent { } export interface IExtensionService { - _serviceBrand: any; + _serviceBrand: undefined; /** * An event emitted when extensions are registered after their extension points got handled. @@ -258,7 +258,7 @@ export function toExtension(extensionDescription: IExtensionDescription): IExten export class NullExtensionService implements IExtensionService { - _serviceBrand: any; + _serviceBrand: undefined; onDidRegisterExtensions: Event = Event.None; onDidChangeExtensionsStatus: Event = Event.None; onDidChangeExtensions: Event = Event.None; diff --git a/src/vs/workbench/services/extensions/common/staticExtensions.ts b/src/vs/workbench/services/extensions/common/staticExtensions.ts index 344f0a5ae7..c12d8c9753 100644 --- a/src/vs/workbench/services/extensions/common/staticExtensions.ts +++ b/src/vs/workbench/services/extensions/common/staticExtensions.ts @@ -12,13 +12,13 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ export const IStaticExtensionsService = createDecorator('IStaticExtensionsService'); export interface IStaticExtensionsService { - _serviceBrand: any; + _serviceBrand: undefined; getExtensions(): Promise; } export class StaticExtensionsService implements IStaticExtensionsService { - _serviceBrand: any; + _serviceBrand: undefined; private readonly _descriptions: IExtensionDescription[] = []; diff --git a/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts b/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts index c0bf439392..b85e5295b5 100644 --- a/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts +++ b/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts @@ -22,7 +22,7 @@ import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagemen export class RemoteExtensionManagementChannelClient extends ExtensionManagementChannelClient { - _serviceBrand: any; + _serviceBrand: undefined; constructor( channel: IChannel, diff --git a/src/vs/workbench/services/extensions/node/extensionPoints.ts b/src/vs/workbench/services/extensions/node/extensionPoints.ts index 84254e6761..499cef4250 100644 --- a/src/vs/workbench/services/extensions/node/extensionPoints.ts +++ b/src/vs/workbench/services/extensions/node/extensionPoints.ts @@ -49,8 +49,9 @@ class ExtensionManifestParser extends ExtensionManifestHandler { public parse(): Promise { return pfs.readFile(this._absoluteManifestPath).then((manifestContents) => { - try { - const manifest = JSON.parse(manifestContents.toString()); + const errors: json.ParseError[] = []; + const manifest = json.parse(manifestContents.toString(), errors); + if (errors.length === 0) { if (manifest.__metadata) { manifest.uuid = manifest.__metadata.id; } @@ -60,8 +61,10 @@ class ExtensionManifestParser extends ExtensionManifestHandler { } delete manifest.__metadata; return manifest; - } catch (e) { - this._log.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: {1}.", this._absoluteManifestPath, getParseErrorMessage(e.message))); + } else { + errors.forEach(e => { + this._log.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: [{1}, {2}] {3}.", this._absoluteManifestPath, e.offset, e.length, getParseErrorMessage(e.error))); + }); } return null; }, (err) => { diff --git a/src/vs/workbench/services/extensions/node/proxyResolver.ts b/src/vs/workbench/services/extensions/node/proxyResolver.ts index 1fa3ce99ce..81812dfc29 100644 --- a/src/vs/workbench/services/extensions/node/proxyResolver.ts +++ b/src/vs/workbench/services/extensions/node/proxyResolver.ts @@ -469,26 +469,24 @@ async function readCaCertificates() { } async function readWindowsCaCertificates() { - // Not using await to work around minifier bug (https://github.com/microsoft/vscode/issues/79044). - return import('vscode-windows-ca-certs') - .then(winCA => { - let ders: any[] = []; - const store = winCA(); - try { - let der: any; - while (der = store.next()) { - ders.push(der); - } - } finally { - store.done(); - } + const winCA = await import('vscode-windows-ca-certs'); - const certs = new Set(ders.map(derToPem)); - return { - certs: Array.from(certs), - append: true - }; - }); + let ders: any[] = []; + const store = winCA(); + try { + let der: any; + while (der = store.next()) { + ders.push(der); + } + } finally { + store.done(); + } + + const certs = new Set(ders.map(derToPem)); + return { + certs: Array.from(certs), + append: true + }; } async function readMacCaCertificates() { diff --git a/src/vs/workbench/services/extensions/worker/extHost.services.ts b/src/vs/workbench/services/extensions/worker/extHost.services.ts index e6e43bfda8..4b6481be30 100644 --- a/src/vs/workbench/services/extensions/worker/extHost.services.ts +++ b/src/vs/workbench/services/extensions/worker/extHost.services.ts @@ -10,7 +10,7 @@ import { IExtHostDecorations, ExtHostDecorations } from 'vs/workbench/api/common import { IExtHostConfiguration, ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration'; import { IExtHostCommands, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; import { IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; -import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService'; +import { IExtHostTerminalService, WorkerExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService'; import { IExtHostTask } from 'vs/workbench/api/common/extHostTask'; import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService'; import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch'; @@ -48,7 +48,7 @@ function NotImplementedProxy(name: ServiceIdentifier): { new(): T } { } }; } -registerSingleton(IExtHostTerminalService, class extends NotImplementedProxy(IExtHostTerminalService) { }); +registerSingleton(IExtHostTerminalService, WorkerExtHostTerminalService); registerSingleton(IExtHostTask, class extends NotImplementedProxy(IExtHostTask) { }); registerSingleton(IExtHostDebugService, class extends NotImplementedProxy(IExtHostDebugService) { }); registerSingleton(IExtHostSearch, class extends NotImplementedProxy(IExtHostSearch) { }); diff --git a/src/vs/workbench/services/extensions/worker/extensionHostWorker.ts b/src/vs/workbench/services/extensions/worker/extensionHostWorker.ts index a1e5513869..fef3f893f2 100644 --- a/src/vs/workbench/services/extensions/worker/extensionHostWorker.ts +++ b/src/vs/workbench/services/extensions/worker/extensionHostWorker.ts @@ -15,6 +15,9 @@ import 'vs/workbench/services/extensions/worker/extHost.services'; //#region --- Define, capture, and override some globals //todo@joh do not allow extensions to call postMessage and other globals... +// declare WorkerSelf#postMessage +declare function postMessage(data: any, transferables?: Transferable[]): void; + declare namespace self { let close: any; let postMessage: any; @@ -38,7 +41,7 @@ self.caches.open = () => console.trace(`'indexedDB.caches' has been blocked`); //#endregion --- const hostUtil = new class implements IHostUtils { - _serviceBrand: any; + _serviceBrand: undefined; exit(_code?: number | undefined): void { nativeClose(); } diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index b298364c60..5f2983b1e1 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -24,7 +24,7 @@ import { getCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { getExcludes, ISearchConfiguration } from 'vs/workbench/services/search/common/search'; import { IExpression } from 'vs/base/common/glob'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; -import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ResourceGlobMatcher } from 'vs/workbench/common/resources'; import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; @@ -99,7 +99,7 @@ interface IRecentlyClosedFile { export class HistoryService extends Disposable implements IHistoryService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private static readonly STORAGE_KEY = 'history.entries'; private static readonly MAX_HISTORY_ITEMS = 200; @@ -120,7 +120,7 @@ export class HistoryService extends Disposable implements IHistoryService { private lastEditLocation: IStackEntry | undefined; - private history: Array; + private history!: Array; private recentlyClosedFiles: IRecentlyClosedFile[]; private loaded: boolean; private resourceFilter: ResourceGlobMatcher; diff --git a/src/vs/workbench/services/history/common/history.ts b/src/vs/workbench/services/history/common/history.ts index 70e56a3ffd..9ac57e50ae 100644 --- a/src/vs/workbench/services/history/common/history.ts +++ b/src/vs/workbench/services/history/common/history.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IResourceInput } from 'vs/platform/editor/common/editor'; import { IEditorInput } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; @@ -12,7 +12,7 @@ export const IHistoryService = createDecorator('historyService' export interface IHistoryService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; /** * Re-opens the last closed editor if any. diff --git a/src/vs/workbench/services/integrity/browser/integrityService.ts b/src/vs/workbench/services/integrity/browser/integrityService.ts index 7bb17c5510..33767222e1 100644 --- a/src/vs/workbench/services/integrity/browser/integrityService.ts +++ b/src/vs/workbench/services/integrity/browser/integrityService.ts @@ -5,11 +5,10 @@ import { IIntegrityService, IntegrityTestResult } from 'vs/workbench/services/integrity/common/integrity'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class BrowserIntegrityServiceImpl implements IIntegrityService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; async isPure(): Promise { return { isPure: true, proof: [] }; diff --git a/src/vs/workbench/services/integrity/common/integrity.ts b/src/vs/workbench/services/integrity/common/integrity.ts index 6e7ceadcb6..246a60c709 100644 --- a/src/vs/workbench/services/integrity/common/integrity.ts +++ b/src/vs/workbench/services/integrity/common/integrity.ts @@ -21,7 +21,7 @@ export interface IntegrityTestResult { } export interface IIntegrityService { - _serviceBrand: any; + _serviceBrand: undefined; isPure(): Promise; } diff --git a/src/vs/workbench/services/integrity/node/integrityService.ts b/src/vs/workbench/services/integrity/node/integrityService.ts index b25b20a8f4..756340e270 100644 --- a/src/vs/workbench/services/integrity/node/integrityService.ts +++ b/src/vs/workbench/services/integrity/node/integrityService.ts @@ -14,7 +14,6 @@ import product from 'vs/platform/product/node/product'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IOpenerService } from 'vs/platform/opener/common/opener'; interface IStorageData { @@ -57,7 +56,7 @@ class IntegrityStorage { export class IntegrityServiceImpl implements IIntegrityService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private _storage: IntegrityStorage; private _isPurePromise: Promise; @@ -87,22 +86,32 @@ export class IntegrityServiceImpl implements IIntegrityService { return; // Do not prompt } - this.notificationService.prompt( - Severity.Warning, - nls.localize('integrity.prompt', "Your {0} installation appears to be corrupt. Please reinstall.", product.nameShort), - [ - { - label: nls.localize('integrity.moreInformation', "More Information"), - run: () => this.openerService.open(URI.parse(product.checksumFailMoreInfoUrl)) - }, - { - label: nls.localize('integrity.dontShowAgain', "Don't Show Again"), - isSecondary: true, - run: () => this._storage.set({ dontShowPrompt: true, commit: product.commit }) - } - ], - { sticky: true } - ); + const checksumFailMoreInfoUrl = product.checksumFailMoreInfoUrl; + const message = nls.localize('integrity.prompt', "Your {0} installation appears to be corrupt. Please reinstall.", product.nameShort); + if (checksumFailMoreInfoUrl) { + this.notificationService.prompt( + Severity.Warning, + message, + [ + { + label: nls.localize('integrity.moreInformation', "More Information"), + run: () => this.openerService.open(URI.parse(checksumFailMoreInfoUrl)) + }, + { + label: nls.localize('integrity.dontShowAgain', "Don't Show Again"), + isSecondary: true, + run: () => this._storage.set({ dontShowPrompt: true, commit: product.commit }) + } + ], + { sticky: true } + ); + } else { + this.notificationService.notify({ + severity: Severity.Warning, + message, + sticky: true + }); + } } isPure(): Promise { diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index 5109c2b008..9dfab8afcf 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -26,7 +26,6 @@ import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKe import { INotificationService } from 'vs/platform/notification/common/notification'; import { Registry } from 'vs/platform/registry/common/platform'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { keybindingsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import { ExtensionMessageCollector, ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { IUserKeybindingItem, KeybindingIO, OutputBuilder } from 'vs/workbench/services/keybinding/common/keybindingIO'; import { IKeyboardMapper } from 'vs/workbench/services/keybinding/common/keyboardMapper'; @@ -226,7 +225,6 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { } })); - keybindingsTelemetry(telemetryService, this); let data = this.keymapService.getCurrentKeyboardLayout(); /* __GDPR__ "keyboardLayout" : { @@ -602,10 +600,12 @@ let commandsSchemas: IJSONSchema[] = []; let commandsEnum: string[] = []; let commandsEnumDescriptions: (string | undefined)[] = []; let schema: IJSONSchema = { - 'id': schemaId, - 'type': 'array', - 'title': nls.localize('keybindings.json.title', "Keybindings configuration"), - 'definitions': { + id: schemaId, + type: 'array', + title: nls.localize('keybindings.json.title', "Keybindings configuration"), + allowsTrailingCommas: true, + allowComments: true, + definitions: { 'editorGroupsSchema': { 'type': 'array', 'items': { @@ -623,7 +623,7 @@ let schema: IJSONSchema = { } } }, - 'items': { + items: { 'required': ['key'], 'type': 'object', 'defaultSnippets': [{ 'body': { 'key': '$1', 'command': '$2', 'when': '$3' } }], diff --git a/src/vs/workbench/services/keybinding/browser/keymapService.ts b/src/vs/workbench/services/keybinding/browser/keymapService.ts index cf8ac659c2..2445acde0b 100644 --- a/src/vs/workbench/services/keybinding/browser/keymapService.ts +++ b/src/vs/workbench/services/keybinding/browser/keymapService.ts @@ -495,7 +495,7 @@ class UserKeyboardLayout extends Disposable { } class BrowserKeymapService extends Disposable implements IKeymapService { - public _serviceBrand: any; + public _serviceBrand: undefined; private readonly _onDidChangeKeyboardMapper = new Emitter(); public readonly onDidChangeKeyboardMapper: Event = this._onDidChangeKeyboardMapper.event; diff --git a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts index 7d74b3ff00..c91b2fd170 100644 --- a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts +++ b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts @@ -20,7 +20,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IFileService } from 'vs/platform/files/common/files'; -import { ServiceIdentifier, createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IUserFriendlyKeybinding } from 'vs/platform/keybinding/common/keybinding'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; @@ -30,7 +30,7 @@ export const IKeybindingEditingService = createDecorator; + _serviceBrand: undefined; editKeybinding(keybindingItem: ResolvedKeybindingItem, key: string, when: string | undefined): Promise; @@ -41,7 +41,7 @@ export interface IKeybindingEditingService { export class KeybindingsEditingService extends Disposable implements IKeybindingEditingService { - public _serviceBrand: any; + public _serviceBrand: undefined; private queue: Queue; private resource: URI = this.environmentService.keybindingsResource; @@ -259,4 +259,4 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding } } -registerSingleton(IKeybindingEditingService, KeybindingsEditingService, true); \ No newline at end of file +registerSingleton(IKeybindingEditingService, KeybindingsEditingService, true); diff --git a/src/vs/workbench/services/keybinding/common/keymapInfo.ts b/src/vs/workbench/services/keybinding/common/keymapInfo.ts index d425d0f1b2..425fa59b65 100644 --- a/src/vs/workbench/services/keybinding/common/keymapInfo.ts +++ b/src/vs/workbench/services/keybinding/common/keymapInfo.ts @@ -5,7 +5,7 @@ import { Event } from 'vs/base/common/event'; import { isWindows, isLinux } from 'vs/base/common/platform'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { DispatchConfig } from 'vs/workbench/services/keybinding/common/dispatchConfig'; import { IKeyboardMapper } from 'vs/workbench/services/keybinding/common/keyboardMapper'; import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; @@ -94,7 +94,7 @@ export type IKeyboardLayoutInfo = (IWindowsKeyboardLayoutInfo | ILinuxKeyboardLa export const IKeymapService = createDecorator('keymapService'); export interface IKeymapService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; onDidChangeKeyboardMapper: Event; getKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper; getCurrentKeyboardLayout(): IKeyboardLayoutInfo | null; diff --git a/src/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts b/src/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts index 5781621052..85d6ffd0e3 100644 --- a/src/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts +++ b/src/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts @@ -239,6 +239,7 @@ export class WindowsKeyboardMapper implements IKeyboardMapper { } let producesLetter: boolean[] = []; + let producesLetters = false; this._codeInfo = []; for (let strCode in rawMappings) { @@ -301,11 +302,13 @@ export class WindowsKeyboardMapper implements IKeyboardMapper { if (charCode >= CharCode.a && charCode <= CharCode.z) { const upperCaseValue = CharCode.A + (charCode - CharCode.a); producesLetter[upperCaseValue] = true; + producesLetters = true; this._keyCodeToLabel[keyCode] = String.fromCharCode(CharCode.A + (charCode - CharCode.a)); } else if (charCode >= CharCode.A && charCode <= CharCode.Z) { producesLetter[charCode] = true; + producesLetters = true; this._keyCodeToLabel[keyCode] = value; } @@ -348,6 +351,30 @@ export class WindowsKeyboardMapper implements IKeyboardMapper { _registerLetterIfMissing(CharCode.X, KeyCode.KEY_X); _registerLetterIfMissing(CharCode.Y, KeyCode.KEY_Y); _registerLetterIfMissing(CharCode.Z, KeyCode.KEY_Z); + + if (!producesLetters) { + // Since this keyboard layout produces no latin letters at all, most of the UI will use the + // US kb layout equivalent for UI labels, so also try to render other keys with the US labels + // for consistency... + const _registerLabel = (keyCode: KeyCode, charCode: CharCode): void => { + // const existingLabel = this._keyCodeToLabel[keyCode]; + // const existingCharCode = (existingLabel ? existingLabel.charCodeAt(0) : CharCode.Null); + // if (existingCharCode < 32 || existingCharCode > 126) { + this._keyCodeToLabel[keyCode] = String.fromCharCode(charCode); + // } + }; + _registerLabel(KeyCode.US_SEMICOLON, CharCode.Semicolon); + _registerLabel(KeyCode.US_EQUAL, CharCode.Equals); + _registerLabel(KeyCode.US_COMMA, CharCode.Comma); + _registerLabel(KeyCode.US_MINUS, CharCode.Dash); + _registerLabel(KeyCode.US_DOT, CharCode.Period); + _registerLabel(KeyCode.US_SLASH, CharCode.Slash); + _registerLabel(KeyCode.US_BACKTICK, CharCode.BackTick); + _registerLabel(KeyCode.US_OPEN_SQUARE_BRACKET, CharCode.OpenSquareBracket); + _registerLabel(KeyCode.US_BACKSLASH, CharCode.Backslash); + _registerLabel(KeyCode.US_CLOSE_SQUARE_BRACKET, CharCode.CloseSquareBracket); + _registerLabel(KeyCode.US_QUOTE, CharCode.SingleQuote); + } } public dumpDebugInfo(): string { diff --git a/src/vs/workbench/services/keybinding/electron-browser/nativeKeymapService.ts b/src/vs/workbench/services/keybinding/electron-browser/nativeKeymapService.ts index 019e0a6404..0d822bac28 100644 --- a/src/vs/workbench/services/keybinding/electron-browser/nativeKeymapService.ts +++ b/src/vs/workbench/services/keybinding/electron-browser/nativeKeymapService.ts @@ -132,7 +132,7 @@ export class KeyboardMapperFactory { } class NativeKeymapService extends Disposable implements IKeymapService { - public _serviceBrand: any; + public _serviceBrand: undefined; private readonly _onDidChangeKeyboardMapper = new Emitter(); public readonly onDidChangeKeyboardMapper: Event = this._onDidChangeKeyboardMapper.event; diff --git a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts index 2cc12ff2c2..5a2db1fbdd 100644 --- a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts @@ -46,14 +46,14 @@ import { Schemas } from 'vs/base/common/network'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { URI } from 'vs/base/common/uri'; import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; class TestEnvironmentService extends WorkbenchEnvironmentService { constructor(private _appSettingsHome: URI) { - super(parseArgs(process.argv) as IWindowConfiguration, process.execPath); + super(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath); } get appSettingsHome() { return this._appSettingsHome; } diff --git a/src/vs/workbench/services/keybinding/test/keyboardMapperTestUtils.ts b/src/vs/workbench/services/keybinding/test/keyboardMapperTestUtils.ts index 0170013ac7..7fcf3e3e5a 100644 --- a/src/vs/workbench/services/keybinding/test/keyboardMapperTestUtils.ts +++ b/src/vs/workbench/services/keybinding/test/keyboardMapperTestUtils.ts @@ -68,7 +68,7 @@ export function assertMapping(writeFileIfDifferent: boolean, mapper: IKeyboardMa let expected = buff.toString(); const actual = mapper.dumpDebugInfo(); if (actual !== expected && writeFileIfDifferent) { - const destPath = filePath.replace(/vscode\/out\/vs/, 'vscode/src/vs'); + const destPath = filePath.replace(/vscode[\/\\]out[\/\\]vs/, 'vscode/src/vs'); writeFile(destPath, actual); } diff --git a/src/vs/workbench/services/keybinding/test/macLinuxFallbackKeyboardMapper.test.ts b/src/vs/workbench/services/keybinding/test/macLinuxFallbackKeyboardMapper.test.ts index eab15ef178..55615dd35f 100644 --- a/src/vs/workbench/services/keybinding/test/macLinuxFallbackKeyboardMapper.test.ts +++ b/src/vs/workbench/services/keybinding/test/macLinuxFallbackKeyboardMapper.test.ts @@ -78,9 +78,9 @@ suite('keyboardMapper - MAC fallback', () => { test('resolveUserBinding Cmd+[Comma] Cmd+/', () => { assertResolveUserBinding( mapper, [ - new ScanCodeBinding(false, false, false, true, ScanCode.Comma), - new SimpleKeybinding(false, false, false, true, KeyCode.US_SLASH), - ], + new ScanCodeBinding(false, false, false, true, ScanCode.Comma), + new SimpleKeybinding(false, false, false, true, KeyCode.US_SLASH), + ], [{ label: '⌘, ⌘/', ariaLabel: 'Command+, Command+/', @@ -183,9 +183,9 @@ suite('keyboardMapper - LINUX fallback', () => { test('resolveUserBinding Ctrl+[Comma] Ctrl+/', () => { assertResolveUserBinding( mapper, [ - new ScanCodeBinding(true, false, false, false, ScanCode.Comma), - new SimpleKeybinding(true, false, false, false, KeyCode.US_SLASH), - ], + new ScanCodeBinding(true, false, false, false, ScanCode.Comma), + new SimpleKeybinding(true, false, false, false, KeyCode.US_SLASH), + ], [{ label: 'Ctrl+, Ctrl+/', ariaLabel: 'Control+, Control+/', @@ -201,8 +201,8 @@ suite('keyboardMapper - LINUX fallback', () => { test('resolveUserBinding Ctrl+[Comma]', () => { assertResolveUserBinding( mapper, [ - new ScanCodeBinding(true, false, false, false, ScanCode.Comma), - ], + new ScanCodeBinding(true, false, false, false, ScanCode.Comma), + ], [{ label: 'Ctrl+,', ariaLabel: 'Control+,', diff --git a/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts b/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts index ff738d1053..3e5bf7b828 100644 --- a/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts +++ b/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts @@ -752,9 +752,9 @@ suite('keyboardMapper - LINUX de_ch', () => { test('resolveUserBinding Ctrl+[Comma] Ctrl+/', () => { assertResolveUserBinding( mapper, [ - new ScanCodeBinding(true, false, false, false, ScanCode.Comma), - new SimpleKeybinding(true, false, false, false, KeyCode.US_SLASH), - ], + new ScanCodeBinding(true, false, false, false, ScanCode.Comma), + new SimpleKeybinding(true, false, false, false, KeyCode.US_SLASH), + ], [{ label: 'Ctrl+, Ctrl+Shift+7', ariaLabel: 'Control+, Control+Shift+7', @@ -1135,9 +1135,9 @@ suite('keyboardMapper - LINUX en_us', () => { test('resolveUserBinding Ctrl+[Comma] Ctrl+/', () => { assertResolveUserBinding( mapper, [ - new ScanCodeBinding(true, false, false, false, ScanCode.Comma), - new SimpleKeybinding(true, false, false, false, KeyCode.US_SLASH), - ], + new ScanCodeBinding(true, false, false, false, ScanCode.Comma), + new SimpleKeybinding(true, false, false, false, KeyCode.US_SLASH), + ], [{ label: 'Ctrl+, Ctrl+/', ariaLabel: 'Control+, Control+/', @@ -1153,8 +1153,8 @@ suite('keyboardMapper - LINUX en_us', () => { test('resolveUserBinding Ctrl+[Comma]', () => { assertResolveUserBinding( mapper, [ - new ScanCodeBinding(true, false, false, false, ScanCode.Comma) - ], + new ScanCodeBinding(true, false, false, false, ScanCode.Comma) + ], [{ label: 'Ctrl+,', ariaLabel: 'Control+,', diff --git a/src/vs/workbench/services/keybinding/test/win_ru.txt b/src/vs/workbench/services/keybinding/test/win_ru.txt index 359a386238..61af5ab16e 100644 --- a/src/vs/workbench/services/keybinding/test/win_ru.txt +++ b/src/vs/workbench/services/keybinding/test/win_ru.txt @@ -203,15 +203,15 @@ | Ctrl+Alt+Equal | --- | Ctrl+Alt+= | Ctrl+Alt+= | ctrl+alt+oem_plus | NO | | Ctrl+Shift+Alt+Equal | --- | Ctrl+Shift+Alt+= | Ctrl+Shift+Alt+= | ctrl+shift+alt+oem_plus | NO | ----------------------------------------------------------------------------------------------------------------------------------------- -| BracketLeft | х | [ | х | oem_4 | NO | -| Shift+BracketLeft | Х | Shift+[ | Shift+х | shift+oem_4 | NO | -| Ctrl+Alt+BracketLeft | --- | Ctrl+Alt+[ | Ctrl+Alt+х | ctrl+alt+oem_4 | NO | -| Ctrl+Shift+Alt+BracketLeft | --- | Ctrl+Shift+Alt+[ | Ctrl+Shift+Alt+х | ctrl+shift+alt+oem_4 | NO | +| BracketLeft | х | [ | [ | oem_4 | NO | +| Shift+BracketLeft | Х | Shift+[ | Shift+[ | shift+oem_4 | NO | +| Ctrl+Alt+BracketLeft | --- | Ctrl+Alt+[ | Ctrl+Alt+[ | ctrl+alt+oem_4 | NO | +| Ctrl+Shift+Alt+BracketLeft | --- | Ctrl+Shift+Alt+[ | Ctrl+Shift+Alt+[ | ctrl+shift+alt+oem_4 | NO | ----------------------------------------------------------------------------------------------------------------------------------------- -| BracketRight | ъ | ] | ъ | oem_6 | NO | -| Shift+BracketRight | Ъ | Shift+] | Shift+ъ | shift+oem_6 | NO | -| Ctrl+Alt+BracketRight | --- | Ctrl+Alt+] | Ctrl+Alt+ъ | ctrl+alt+oem_6 | NO | -| Ctrl+Shift+Alt+BracketRight | --- | Ctrl+Shift+Alt+] | Ctrl+Shift+Alt+ъ | ctrl+shift+alt+oem_6 | NO | +| BracketRight | ъ | ] | ] | oem_6 | NO | +| Shift+BracketRight | Ъ | Shift+] | Shift+] | shift+oem_6 | NO | +| Ctrl+Alt+BracketRight | --- | Ctrl+Alt+] | Ctrl+Alt+] | ctrl+alt+oem_6 | NO | +| Ctrl+Shift+Alt+BracketRight | --- | Ctrl+Shift+Alt+] | Ctrl+Shift+Alt+] | ctrl+shift+alt+oem_6 | NO | ----------------------------------------------------------------------------------------------------------------------------------------- | Backslash | \ | \ | \ | oem_5 | NO | | Shift+Backslash | / | Shift+\ | Shift+\ | shift+oem_5 | NO | @@ -225,35 +225,35 @@ ----------------------------------------------------------------------------------------------------------------------------------------- | HW Code combination | Key | KeyCode combination | UI label | User settings | WYSIWYG | ----------------------------------------------------------------------------------------------------------------------------------------- -| Semicolon | ж | ; | ж | oem_1 | NO | -| Shift+Semicolon | Ж | Shift+; | Shift+ж | shift+oem_1 | NO | -| Ctrl+Alt+Semicolon | --- | Ctrl+Alt+; | Ctrl+Alt+ж | ctrl+alt+oem_1 | NO | -| Ctrl+Shift+Alt+Semicolon | --- | Ctrl+Shift+Alt+; | Ctrl+Shift+Alt+ж | ctrl+shift+alt+oem_1 | NO | +| Semicolon | ж | ; | ; | oem_1 | NO | +| Shift+Semicolon | Ж | Shift+; | Shift+; | shift+oem_1 | NO | +| Ctrl+Alt+Semicolon | --- | Ctrl+Alt+; | Ctrl+Alt+; | ctrl+alt+oem_1 | NO | +| Ctrl+Shift+Alt+Semicolon | --- | Ctrl+Shift+Alt+; | Ctrl+Shift+Alt+; | ctrl+shift+alt+oem_1 | NO | ----------------------------------------------------------------------------------------------------------------------------------------- -| Quote | э | ' | э | oem_7 | NO | -| Shift+Quote | Э | Shift+' | Shift+э | shift+oem_7 | NO | -| Ctrl+Alt+Quote | --- | Ctrl+Alt+' | Ctrl+Alt+э | ctrl+alt+oem_7 | NO | -| Ctrl+Shift+Alt+Quote | --- | Ctrl+Shift+Alt+' | Ctrl+Shift+Alt+э | ctrl+shift+alt+oem_7 | NO | +| Quote | э | ' | ' | oem_7 | NO | +| Shift+Quote | Э | Shift+' | Shift+' | shift+oem_7 | NO | +| Ctrl+Alt+Quote | --- | Ctrl+Alt+' | Ctrl+Alt+' | ctrl+alt+oem_7 | NO | +| Ctrl+Shift+Alt+Quote | --- | Ctrl+Shift+Alt+' | Ctrl+Shift+Alt+' | ctrl+shift+alt+oem_7 | NO | ----------------------------------------------------------------------------------------------------------------------------------------- -| Backquote | ё | ` | ё | oem_3 | NO | -| Shift+Backquote | Ё | Shift+` | Shift+ё | shift+oem_3 | NO | -| Ctrl+Alt+Backquote | --- | Ctrl+Alt+` | Ctrl+Alt+ё | ctrl+alt+oem_3 | NO | -| Ctrl+Shift+Alt+Backquote | --- | Ctrl+Shift+Alt+` | Ctrl+Shift+Alt+ё | ctrl+shift+alt+oem_3 | NO | +| Backquote | ё | ` | ` | oem_3 | NO | +| Shift+Backquote | Ё | Shift+` | Shift+` | shift+oem_3 | NO | +| Ctrl+Alt+Backquote | --- | Ctrl+Alt+` | Ctrl+Alt+` | ctrl+alt+oem_3 | NO | +| Ctrl+Shift+Alt+Backquote | --- | Ctrl+Shift+Alt+` | Ctrl+Shift+Alt+` | ctrl+shift+alt+oem_3 | NO | ----------------------------------------------------------------------------------------------------------------------------------------- -| Comma | б | , | б | oem_comma | NO | -| Shift+Comma | Б | Shift+, | Shift+б | shift+oem_comma | NO | -| Ctrl+Alt+Comma | --- | Ctrl+Alt+, | Ctrl+Alt+б | ctrl+alt+oem_comma | NO | -| Ctrl+Shift+Alt+Comma | --- | Ctrl+Shift+Alt+, | Ctrl+Shift+Alt+б | ctrl+shift+alt+oem_comma | NO | +| Comma | б | , | , | oem_comma | NO | +| Shift+Comma | Б | Shift+, | Shift+, | shift+oem_comma | NO | +| Ctrl+Alt+Comma | --- | Ctrl+Alt+, | Ctrl+Alt+, | ctrl+alt+oem_comma | NO | +| Ctrl+Shift+Alt+Comma | --- | Ctrl+Shift+Alt+, | Ctrl+Shift+Alt+, | ctrl+shift+alt+oem_comma | NO | ----------------------------------------------------------------------------------------------------------------------------------------- -| Period | ю | . | ю | oem_period | NO | -| Shift+Period | Ю | Shift+. | Shift+ю | shift+oem_period | NO | -| Ctrl+Alt+Period | --- | Ctrl+Alt+. | Ctrl+Alt+ю | ctrl+alt+oem_period | NO | -| Ctrl+Shift+Alt+Period | --- | Ctrl+Shift+Alt+. | Ctrl+Shift+Alt+ю | ctrl+shift+alt+oem_period | NO | +| Period | ю | . | . | oem_period | NO | +| Shift+Period | Ю | Shift+. | Shift+. | shift+oem_period | NO | +| Ctrl+Alt+Period | --- | Ctrl+Alt+. | Ctrl+Alt+. | ctrl+alt+oem_period | NO | +| Ctrl+Shift+Alt+Period | --- | Ctrl+Shift+Alt+. | Ctrl+Shift+Alt+. | ctrl+shift+alt+oem_period | NO | ----------------------------------------------------------------------------------------------------------------------------------------- -| Slash | . | / | . | oem_2 | NO | -| Shift+Slash | , | Shift+/ | Shift+. | shift+oem_2 | NO | -| Ctrl+Alt+Slash | --- | Ctrl+Alt+/ | Ctrl+Alt+. | ctrl+alt+oem_2 | NO | -| Ctrl+Shift+Alt+Slash | --- | Ctrl+Shift+Alt+/ | Ctrl+Shift+Alt+. | ctrl+shift+alt+oem_2 | NO | +| Slash | . | / | / | oem_2 | NO | +| Shift+Slash | , | Shift+/ | Shift+/ | shift+oem_2 | NO | +| Ctrl+Alt+Slash | --- | Ctrl+Alt+/ | Ctrl+Alt+/ | ctrl+alt+oem_2 | NO | +| Ctrl+Shift+Alt+Slash | --- | Ctrl+Shift+Alt+/ | Ctrl+Shift+Alt+/ | ctrl+shift+alt+oem_2 | NO | ----------------------------------------------------------------------------------------------------------------------------------------- | HW Code combination | Key | KeyCode combination | UI label | User settings | WYSIWYG | ----------------------------------------------------------------------------------------------------------------------------------------- diff --git a/src/vs/workbench/services/keybinding/test/windowsKeyboardMapper.test.ts b/src/vs/workbench/services/keybinding/test/windowsKeyboardMapper.test.ts index edf5c3df8c..1afd85ed15 100644 --- a/src/vs/workbench/services/keybinding/test/windowsKeyboardMapper.test.ts +++ b/src/vs/workbench/services/keybinding/test/windowsKeyboardMapper.test.ts @@ -280,9 +280,9 @@ suite('keyboardMapper - WINDOWS de_ch', () => { test('resolveUserBinding Ctrl+[Comma] Ctrl+/', () => { assertResolveUserBinding( mapper, [ - new ScanCodeBinding(true, false, false, false, ScanCode.Comma), - new SimpleKeybinding(true, false, false, false, KeyCode.US_SLASH), - ], + new ScanCodeBinding(true, false, false, false, ScanCode.Comma), + new SimpleKeybinding(true, false, false, false, KeyCode.US_SLASH), + ], [{ label: 'Ctrl+, Ctrl+§', ariaLabel: 'Control+, Control+§', @@ -351,9 +351,9 @@ suite('keyboardMapper - WINDOWS en_us', () => { test('resolveUserBinding Ctrl+[Comma] Ctrl+/', () => { assertResolveUserBinding( mapper, [ - new ScanCodeBinding(true, false, false, false, ScanCode.Comma), - new SimpleKeybinding(true, false, false, false, KeyCode.US_SLASH), - ], + new ScanCodeBinding(true, false, false, false, ScanCode.Comma), + new SimpleKeybinding(true, false, false, false, KeyCode.US_SLASH), + ], [{ label: 'Ctrl+, Ctrl+/', ariaLabel: 'Control+, Control+/', @@ -369,8 +369,8 @@ suite('keyboardMapper - WINDOWS en_us', () => { test('resolveUserBinding Ctrl+[Comma]', () => { assertResolveUserBinding( mapper, [ - new ScanCodeBinding(true, false, false, false, ScanCode.Comma), - ], + new ScanCodeBinding(true, false, false, false, ScanCode.Comma), + ], [{ label: 'Ctrl+,', ariaLabel: 'Control+,', diff --git a/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index 20fcc21ea0..4ba782f8e6 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -17,7 +17,6 @@ import { isWindows } from 'vs/base/common/platform'; import { tildify, getPathLabel } from 'vs/base/common/labels'; import { ltrim, endsWith } from 'vs/base/common/strings'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, WORKSPACE_EXTENSION, toWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { Schemas } from 'vs/base/common/network'; import { ILabelService, ResourceLabelFormatter, ResourceLabelFormatting } from 'vs/platform/label/common/label'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { match } from 'vs/base/common/glob'; @@ -92,7 +91,7 @@ class ResourceLabelFormattersHandler implements IWorkbenchContribution { Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ResourceLabelFormattersHandler, LifecyclePhase.Restored); export class LabelService implements ILabelService { - _serviceBrand: any; + _serviceBrand: undefined; private formatters: ResourceLabelFormatter[] = []; private readonly _onDidChangeFormatters = new Emitter(); @@ -283,12 +282,8 @@ export class LabelService implements ILabelService { } private appendWorkspaceSuffix(label: string, uri: URI): string { - if (uri.scheme === Schemas.file) { - return label; - } - const formatting = this.findFormatting(uri); - const suffix = formatting && (typeof formatting.workspaceSuffix === 'string') ? formatting.workspaceSuffix : uri.scheme; + const suffix = formatting && (typeof formatting.workspaceSuffix === 'string') ? formatting.workspaceSuffix : undefined; return suffix ? `${label} [${suffix}]` : label; } } diff --git a/src/vs/workbench/services/layout/browser/layoutService.ts b/src/vs/workbench/services/layout/browser/layoutService.ts index 0b9daa5dcd..019f7b0dae 100644 --- a/src/vs/workbench/services/layout/browser/layoutService.ts +++ b/src/vs/workbench/services/layout/browser/layoutService.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ServiceIdentifier, createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; import { MenuBarVisibility } from 'vs/platform/windows/common/windows'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; @@ -34,7 +34,7 @@ export interface ILayoutOptions { export interface IWorkbenchLayoutService extends ILayoutService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; /** * Emits when the visibility of the title bar changes. @@ -144,6 +144,11 @@ export interface IWorkbenchLayoutService extends ILayoutService { */ setPanelPosition(position: Position): void; + /** + * Gets the maximum possible size for editor. + */ + getMaximumEditorDimensions(): Dimension; + /** * Returns the element that is parent of the workbench element. */ diff --git a/src/vs/workbench/services/notification/common/notificationService.ts b/src/vs/workbench/services/notification/common/notificationService.ts index 649b73c9bb..ccbb5ad56b 100644 --- a/src/vs/workbench/services/notification/common/notificationService.ts +++ b/src/vs/workbench/services/notification/common/notificationService.ts @@ -9,13 +9,12 @@ import { INotificationsModel, NotificationsModel, ChoiceAction } from 'vs/workbe import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IAction, Action } from 'vs/base/common/actions'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; export class NotificationService extends Disposable implements INotificationService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private _model: INotificationsModel = this._register(new NotificationsModel()); diff --git a/src/vs/workbench/services/output/common/outputChannelModel.ts b/src/vs/workbench/services/output/common/outputChannelModel.ts index fe74ffb546..dc088dcc84 100644 --- a/src/vs/workbench/services/output/common/outputChannelModel.ts +++ b/src/vs/workbench/services/output/common/outputChannelModel.ts @@ -31,7 +31,7 @@ export interface IOutputChannelModel extends IDisposable { export const IOutputChannelModelService = createDecorator('outputChannelModelService'); export interface IOutputChannelModelService { - _serviceBrand: any; + _serviceBrand: undefined; createOutputChannelModel(id: string, modelUri: URI, mimeType: string, file?: URI): IOutputChannelModel; diff --git a/src/vs/workbench/services/output/common/outputChannelModelService.ts b/src/vs/workbench/services/output/common/outputChannelModelService.ts index 7a90143ce0..45f9d2f983 100644 --- a/src/vs/workbench/services/output/common/outputChannelModelService.ts +++ b/src/vs/workbench/services/output/common/outputChannelModelService.ts @@ -7,7 +7,7 @@ import { IOutputChannelModelService, AsbtractOutputChannelModelService } from 'v import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class OutputChannelModelService extends AsbtractOutputChannelModelService implements IOutputChannelModelService { - _serviceBrand: any; + _serviceBrand: undefined; } registerSingleton(IOutputChannelModelService, OutputChannelModelService); diff --git a/src/vs/workbench/services/output/node/outputChannelModelService.ts b/src/vs/workbench/services/output/node/outputChannelModelService.ts index 59e17d0c52..e4749c8fe5 100644 --- a/src/vs/workbench/services/output/node/outputChannelModelService.ts +++ b/src/vs/workbench/services/output/node/outputChannelModelService.ts @@ -198,7 +198,7 @@ class DelegatedOutputChannelModel extends Disposable implements IOutputChannelMo export class OutputChannelModelService extends AsbtractOutputChannelModelService implements IOutputChannelModelService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @IInstantiationService instantiationService: IInstantiationService, diff --git a/src/vs/workbench/services/panel/common/panelService.ts b/src/vs/workbench/services/panel/common/panelService.ts index a9a1d73645..c22f2da284 100644 --- a/src/vs/workbench/services/panel/common/panelService.ts +++ b/src/vs/workbench/services/panel/common/panelService.ts @@ -5,7 +5,7 @@ import { Event } from 'vs/base/common/event'; import { IPanel } from 'vs/workbench/common/panel'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IBadge } from 'vs/workbench/services/activity/common/activity'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IProgressIndicator } from 'vs/platform/progress/common/progress'; @@ -20,7 +20,7 @@ export interface IPanelIdentifier { export interface IPanelService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; readonly onDidPanelOpen: Event<{ panel: IPanel, focus: boolean }>; readonly onDidPanelClose: Event; diff --git a/src/vs/workbench/services/preferences/browser/preferencesService.ts b/src/vs/workbench/services/preferences/browser/preferencesService.ts index cc84789e92..c6676efd0a 100644 --- a/src/vs/workbench/services/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/services/preferences/browser/preferencesService.ts @@ -44,7 +44,7 @@ const emptyEditableSettingsContent = '{\n}'; export class PreferencesService extends Disposable implements IPreferencesService { - _serviceBrand: any; + _serviceBrand: undefined; private lastOpenedSettingsInput: PreferencesEditorInput | null = null; @@ -214,7 +214,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic private openSettings2(options?: ISettingsEditorOptions): Promise { const input = this.settingsEditor2Input; - return this.editorService.openEditor(input, options) + return this.editorService.openEditor(input, options ? SettingsEditorOptions.create(options) : undefined) .then(() => this.editorGroupService.activeGroup.activeControl!); } diff --git a/src/vs/workbench/services/preferences/common/preferences.ts b/src/vs/workbench/services/preferences/common/preferences.ts index 4ae383dcb2..f961a01862 100644 --- a/src/vs/workbench/services/preferences/common/preferences.ts +++ b/src/vs/workbench/services/preferences/common/preferences.ts @@ -183,7 +183,7 @@ export interface IKeybindingsEditorModel extends IPreferencesEditorModel { export const IPreferencesService = createDecorator('preferencesService'); export interface IPreferencesService { - _serviceBrand: any; + _serviceBrand: undefined; userSettingsResource: URI; workspaceSettingsResource: URI | null; diff --git a/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts b/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts index ddd0314c10..fa2ec956f3 100644 --- a/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts +++ b/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts @@ -21,7 +21,7 @@ export class PreferencesEditorInput extends SideBySideEditorInput { return PreferencesEditorInput.ID; } - getTitle(verbosity: Verbosity): string | null { + getTitle(verbosity: Verbosity): string | undefined { return this.master.getTitle(verbosity); } } @@ -60,7 +60,7 @@ export class KeybindingsEditorInput extends EditorInput { static readonly ID: string = 'workbench.input.keybindings'; readonly keybindingsModel: KeybindingsEditorModel; - searchOptions: IKeybindingsEditorSearchOptions | null; + searchOptions: IKeybindingsEditorSearchOptions | null = null; constructor(@IInstantiationService instantiationService: IInstantiationService) { super(); diff --git a/src/vs/workbench/services/preferences/common/preferencesModels.ts b/src/vs/workbench/services/preferences/common/preferencesModels.ts index 0a13080f8c..243e085d26 100644 --- a/src/vs/workbench/services/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/services/preferences/common/preferencesModels.ts @@ -1043,6 +1043,13 @@ export function createValidator(prop: IConfigurationPropertySchema): (value: any const stringArrayValue = value as string[]; + if (prop.uniqueItems) { + if (new Set(stringArrayValue).size < stringArrayValue.length) { + message += nls.localize('validations.stringArrayUniqueItems', 'Array has duplicate items'); + message += '\n'; + } + } + if (prop.minItems && stringArrayValue.length < prop.minItems) { message += nls.localize('validations.stringArrayMinItem', 'Array must have at least {0} items', prop.minItems); message += '\n'; diff --git a/src/vs/workbench/services/preferences/test/common/preferencesModel.test.ts b/src/vs/workbench/services/preferences/test/common/preferencesModel.test.ts index 624cfca1bd..4b5d9ed273 100644 --- a/src/vs/workbench/services/preferences/test/common/preferencesModel.test.ts +++ b/src/vs/workbench/services/preferences/test/common/preferencesModel.test.ts @@ -328,4 +328,10 @@ suite('Preferences Model test', () => { arr.rejects(['a']).withMessage(`err: must be friendly`); }); + + test('uniqueItems', () => { + const arr = new ArrayTester({ type: 'array', items: { type: 'string' }, uniqueItems: true }); + + arr.rejects(['a', 'a']).withMessage(`Array has duplicate items`); + }); }); diff --git a/src/vs/workbench/services/progress/browser/editorProgressService.ts b/src/vs/workbench/services/progress/browser/editorProgressService.ts index 931cb44f60..60392f50e4 100644 --- a/src/vs/workbench/services/progress/browser/editorProgressService.ts +++ b/src/vs/workbench/services/progress/browser/editorProgressService.ts @@ -3,11 +3,9 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IEditorProgressService } from 'vs/platform/progress/common/progress'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { ProgressBarIndicator } from 'vs/workbench/services/progress/browser/progressIndicator'; export class EditorProgressService extends ProgressBarIndicator { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; } diff --git a/src/vs/workbench/services/progress/browser/progressService.ts b/src/vs/workbench/services/progress/browser/progressService.ts index d07d39ba51..8b2d6e8ab0 100644 --- a/src/vs/workbench/services/progress/browser/progressService.ts +++ b/src/vs/workbench/services/progress/browser/progressService.ts @@ -23,12 +23,11 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { EventHelper } from 'vs/base/browser/dom'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; export class ProgressService extends Disposable implements IProgressService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private readonly stack: [IProgressOptions, Progress][] = []; private readonly globalStatusEntry = this._register(new MutableDisposable()); @@ -205,10 +204,6 @@ export class ProgressService extends Disposable implements IProgressService { updateProgress(handle, increment); Event.once(handle.onDidClose)(() => { - if (typeof onDidCancel === 'function') { - onDidCancel(); - } - toDispose.dispose(); }); diff --git a/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts b/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts index 43c5388ca2..e124d390ae 100644 --- a/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts +++ b/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts @@ -30,7 +30,10 @@ export class RemoteAgentService extends AbstractRemoteAgentService implements IR super(environmentService); this.socketFactory = new BrowserSocketFactory(webSocketFactory); - this._connection = this._register(new RemoteAgentConnection(environmentService.configuration.remoteAuthority!, productService.commit, this.socketFactory, remoteAuthorityResolverService, signService, logService)); + const remoteAuthority = environmentService.configuration.remoteAuthority; + if (remoteAuthority) { + this._connection = this._register(new RemoteAgentConnection(remoteAuthority, productService.commit, this.socketFactory, remoteAuthorityResolverService, signService, logService)); + } } getConnection(): IRemoteAgentConnection | null { diff --git a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts index b524881df1..fa0b8296ca 100644 --- a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts +++ b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts @@ -24,7 +24,7 @@ import { ILogService } from 'vs/platform/log/common/log'; export abstract class AbstractRemoteAgentService extends Disposable { - _serviceBrand: any; + _serviceBrand: undefined; private _environment: Promise | null; diff --git a/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts b/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts index a04175a44e..9b54131673 100644 --- a/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts +++ b/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts @@ -14,7 +14,7 @@ import { RemoteAuthorities } from 'vs/base/common/network'; export interface IGetEnvironmentDataArguments { language: string; remoteAuthority: string; - extensionDevelopmentPath: UriComponents | UriComponents[] | undefined; + extensionDevelopmentPath: UriComponents[] | undefined; } export interface IRemoteAgentEnvironmentDTO { diff --git a/src/vs/workbench/services/remote/common/remoteAgentService.ts b/src/vs/workbench/services/remote/common/remoteAgentService.ts index 9f18d97423..dba56ecae4 100644 --- a/src/vs/workbench/services/remote/common/remoteAgentService.ts +++ b/src/vs/workbench/services/remote/common/remoteAgentService.ts @@ -15,7 +15,7 @@ export const RemoteExtensionLogFileName = 'remoteagent'; export const IRemoteAgentService = createDecorator('remoteAgentService'); export interface IRemoteAgentService { - _serviceBrand: any; + _serviceBrand: undefined; readonly socketFactory: ISocketFactory; diff --git a/src/vs/workbench/services/remote/node/tunnelService.ts b/src/vs/workbench/services/remote/node/tunnelService.ts index 574396f14e..055dbb7817 100644 --- a/src/vs/workbench/services/remote/node/tunnelService.ts +++ b/src/vs/workbench/services/remote/node/tunnelService.ts @@ -86,7 +86,7 @@ class NodeRemoteTunnel extends Disposable implements RemoteTunnel { } export class TunnelService implements ITunnelService { - _serviceBrand: any; + _serviceBrand: undefined; public constructor( @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, diff --git a/src/vs/workbench/services/search/common/replace.ts b/src/vs/workbench/services/search/common/replace.ts index a7554be51a..a180601f43 100644 --- a/src/vs/workbench/services/search/common/replace.ts +++ b/src/vs/workbench/services/search/common/replace.ts @@ -27,7 +27,7 @@ export class ReplacePattern { } else { searchPatternInfo = arg2; parseParameters = !!searchPatternInfo.isRegExp; - this._regExp = strings.createRegExp(searchPatternInfo.pattern, !!searchPatternInfo.isRegExp, { matchCase: searchPatternInfo.isCaseSensitive, wholeWord: searchPatternInfo.isWordMatch, multiline: searchPatternInfo.isMultiline, global: false }); + this._regExp = strings.createRegExp(searchPatternInfo.pattern, !!searchPatternInfo.isRegExp, { matchCase: searchPatternInfo.isCaseSensitive, wholeWord: searchPatternInfo.isWordMatch, multiline: searchPatternInfo.isMultiline, global: false, unicode: true }); } if (parseParameters) { diff --git a/src/vs/workbench/services/search/common/search.ts b/src/vs/workbench/services/search/common/search.ts index 959f088658..5279cf20d5 100644 --- a/src/vs/workbench/services/search/common/search.ts +++ b/src/vs/workbench/services/search/common/search.ts @@ -32,7 +32,7 @@ export const ISearchService = createDecorator('searchService'); * A service that enables to search for files or with in files. */ export interface ISearchService { - _serviceBrand: any; + _serviceBrand: undefined; textSearch(query: ITextQuery, token?: CancellationToken, onProgress?: (result: ISearchProgressItem) => void): Promise; fileSearch(query: IFileQuery, token?: CancellationToken): Promise; clearCache(cacheKey: string): Promise; @@ -132,6 +132,7 @@ export interface IPatternInfo { isWordMatch?: boolean; wordSeparators?: string; isMultiline?: boolean; + isUnicode?: boolean; isCaseSensitive?: boolean; } @@ -516,7 +517,7 @@ export class QueryGlobTester { private _excludeExpression: glob.IExpression; private _parsedExcludeExpression: glob.ParsedExpression; - private _parsedIncludeExpression: glob.ParsedExpression; + private _parsedIncludeExpression: glob.ParsedExpression | null = null; constructor(config: ISearchQuery, folderQuery: IFolderQuery) { this._excludeExpression = { diff --git a/src/vs/workbench/services/search/common/searchExtTypes.ts b/src/vs/workbench/services/search/common/searchExtTypes.ts index d76a55bb08..806c026621 100644 --- a/src/vs/workbench/services/search/common/searchExtTypes.ts +++ b/src/vs/workbench/services/search/common/searchExtTypes.ts @@ -33,8 +33,8 @@ export class Range { this.end = new Position(endLine, endCol); } - isEmpty: boolean; - isSingleLine: boolean; + isEmpty = false; + isSingleLine = false; contains(positionOrRange: Position | Range): boolean { return false; } isEqual(other: Range): boolean { return false; } intersection(range: Range): Range | undefined { return undefined; } @@ -410,4 +410,4 @@ export interface FindTextInFilesOptions { * Number of lines of context to include after each match. */ afterContext?: number; -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/search/common/searchService.ts b/src/vs/workbench/services/search/common/searchService.ts index cabe361a30..db5d626296 100644 --- a/src/vs/workbench/services/search/common/searchService.ts +++ b/src/vs/workbench/services/search/common/searchService.ts @@ -21,13 +21,12 @@ import { deserializeSearchError, FileMatch, ICachedSearchStats, IFileMatch, IFil import { addContextToEditorMatches, editorMatchesToTextSearchResults } from 'vs/workbench/services/search/common/searchHelpers'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class SearchService extends Disposable implements ISearchService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; - protected diskSearch: ISearchResultProvider; + protected diskSearch: ISearchResultProvider | null = null; private readonly fileSearchProviders = new Map(); private readonly textSearchProviders = new Map(); diff --git a/src/vs/workbench/services/search/node/fileSearch.ts b/src/vs/workbench/services/search/node/fileSearch.ts index 1b80a9ac46..0973cd61af 100644 --- a/src/vs/workbench/services/search/node/fileSearch.ts +++ b/src/vs/workbench/services/search/node/fileSearch.ts @@ -43,20 +43,20 @@ process.on('exit', () => { export class FileWalker { private config: IFileQuery; private filePattern: string; - private normalizedFilePatternLowercase: string; + private normalizedFilePatternLowercase: string | null = null; private includePattern: glob.ParsedExpression | undefined; private maxResults: number | null; private exists: boolean; - private maxFilesize: number | null; + private maxFilesize: number | null = null; private isLimitHit: boolean; private resultCount: number; - private isCanceled: boolean; - private fileWalkSW: StopWatch; + private isCanceled = false; + private fileWalkSW: StopWatch | null = null; private directoriesWalked: number; private filesWalked: number; private errors: string[]; - private cmdSW: StopWatch; - private cmdResultCount: number; + private cmdSW: StopWatch | null = null; + private cmdResultCount: number = 0; private folderExcludePatterns: Map; private globalExcludePattern: glob.ParsedExpression | undefined; @@ -139,8 +139,8 @@ export class FileWalker { rootFolderDone(null, undefined); } }); - }, (errors, result) => { - this.fileWalkSW.stop(); + }, (errors, _result) => { + this.fileWalkSW!.stop(); const err = errors ? arrays.coalesce(errors)[0] : null; done(err, this.isLimitHit); }); @@ -455,8 +455,8 @@ export class FileWalker { getStats(): ISearchEngineStats { return { - cmdTime: this.cmdSW && this.cmdSW.elapsed(), - fileWalkTime: this.fileWalkSW.elapsed(), + cmdTime: this.cmdSW!.elapsed(), + fileWalkTime: this.fileWalkSW!.elapsed(), directoriesWalked: this.directoriesWalked, filesWalked: this.filesWalked, cmdResultCount: this.cmdResultCount @@ -578,7 +578,9 @@ export class FileWalker { return true; // support the all-matching wildcard } - return strings.fuzzyContains(path, this.normalizedFilePatternLowercase); + if (this.normalizedFilePatternLowercase) { + return strings.fuzzyContains(path, this.normalizedFilePatternLowercase); + } } // No patterns means we match all diff --git a/src/vs/workbench/services/search/node/rawSearchService.ts b/src/vs/workbench/services/search/node/rawSearchService.ts index 497f00611b..4bc07a28c1 100644 --- a/src/vs/workbench/services/search/node/rawSearchService.ts +++ b/src/vs/workbench/services/search/node/rawSearchService.ts @@ -254,7 +254,7 @@ export class SearchService implements IRawSearchService { const query = prepareQuery(config.filePattern || ''); const compare = (matchA: IRawFileMatch, matchB: IRawFileMatch) => compareItemsByScore(matchA, matchB, query, true, FileMatchItemAccessor, scorerCache); - const maxResults = config.maxResults || Number.MAX_VALUE; + const maxResults = typeof config.maxResults === 'number' ? config.maxResults : Number.MAX_VALUE; return arrays.topAsync(results, compare, maxResults, 10000, token); } diff --git a/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts b/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts index 649e6a2d39..c42ab60aa1 100644 --- a/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts +++ b/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts @@ -394,13 +394,11 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[] args.push('--encoding', options.encoding); } - let pattern = query.pattern; - // Ripgrep handles -- as a -- arg separator. Only --. // - is ok, --- is ok, --some-flag is also ok. Need to special case. - if (pattern === '--') { + if (query.pattern === '--') { query.isRegExp = true; - pattern = '\\-\\-'; + query.pattern = '\\-\\-'; } if (query.isMultiline && !query.isRegExp) { @@ -413,7 +411,7 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[] } if (query.isRegExp) { - pattern = unicodeEscapesToPCRE2(pattern); + query.pattern = unicodeEscapesToPCRE2(query.pattern); } // Allow $ to match /r/n @@ -421,7 +419,7 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[] let searchPatternAfterDoubleDashes: Maybe; if (query.isWordMatch) { - const regexp = createRegExp(pattern, !!query.isRegExp, { wholeWord: query.isWordMatch }); + const regexp = createRegExp(query.pattern, !!query.isRegExp, { wholeWord: query.isWordMatch }); const regexpStr = regexp.source.replace(/\\\//g, '/'); // RegExp.source arbitrarily returns escaped slashes. Search and destroy. args.push('--regexp', regexpStr); } else if (query.isRegExp) { @@ -430,7 +428,7 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[] args.push('--regexp', fixedRegexpQuery); args.push('--auto-hybrid-regex'); } else { - searchPatternAfterDoubleDashes = pattern; + searchPatternAfterDoubleDashes = query.pattern; args.push('--fixed-strings'); } @@ -479,11 +477,18 @@ export function spreadGlobComponents(globArg: string): string[] { } export function unicodeEscapesToPCRE2(pattern: string): string { - const reg = /((?:[^\\]|^)(?:\\\\)*)\\u([a-z0-9]{4})(?!\d)/g; - // Replace an unescaped $ at the end of the pattern with \r?$ - // Match $ preceeded by none or even number of literal \ - while (pattern.match(reg)) { - pattern = pattern.replace(reg, `$1\\x{$2}`); + // Match \u1234 + const unicodePattern = /((?:[^\\]|^)(?:\\\\)*)\\u([a-z0-9]{4})/g; + + while (pattern.match(unicodePattern)) { + pattern = pattern.replace(unicodePattern, `$1\\x{$2}`); + } + + // Match \u{1234} + // \u with 5-6 characters will be left alone because \x only takes 4 characters. + const unicodePatternWithBraces = /((?:[^\\]|^)(?:\\\\)*)\\u\{([a-z0-9]{4})\}/g; + while (pattern.match(unicodePatternWithBraces)) { + pattern = pattern.replace(unicodePatternWithBraces, `$1\\x{$2}`); } return pattern; diff --git a/src/vs/workbench/services/search/node/textSearchManager.ts b/src/vs/workbench/services/search/node/textSearchManager.ts index 876864d49e..5e16591a94 100644 --- a/src/vs/workbench/services/search/node/textSearchManager.ts +++ b/src/vs/workbench/services/search/node/textSearchManager.ts @@ -7,8 +7,8 @@ import * as path from 'vs/base/common/path'; import { mapArrayOrNot } from 'vs/base/common/arrays'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { toErrorMessage } from 'vs/base/common/errorMessage'; -import * as glob from 'vs/base/common/glob'; import * as resources from 'vs/base/common/resources'; +import * as glob from 'vs/base/common/glob'; import { URI } from 'vs/base/common/uri'; import { toCanonicalName } from 'vs/base/node/encoding'; import * as pfs from 'vs/base/node/pfs'; @@ -17,9 +17,9 @@ import { TextSearchProvider, TextSearchResult, TextSearchMatch, TextSearchComple export class TextSearchManager { - private collector: TextSearchResultsCollector; + private collector: TextSearchResultsCollector | null = null; - private isLimitHit: boolean; + private isLimitHit = false; private resultCount = 0; constructor(private query: ITextQuery, private provider: TextSearchProvider, private _pfs: typeof pfs = pfs) { @@ -52,7 +52,7 @@ export class TextSearchManager { const newResultSize = this.resultSize(result); this.resultCount += newResultSize; if (newResultSize > 0) { - this.collector.add(result, folderIdx); + this.collector!.add(result, folderIdx); } } }; @@ -62,7 +62,7 @@ export class TextSearchManager { return this.searchInFolder(fq, r => onResult(r, i), tokenSource.token); })).then(results => { tokenSource.dispose(); - this.collector.flush(); + this.collector!.flush(); const someFolderHitLImit = results.some(result => !!result && !!result.limitHit); resolve({ @@ -198,8 +198,8 @@ function patternInfoToQuery(patternInfo: IPatternInfo): TextSearchQuery { export class TextSearchResultsCollector { private _batchedCollector: BatchedCollector; - private _currentFolderIdx: number; - private _currentUri: URI; + private _currentFolderIdx: number = -1; + private _currentUri: URI | undefined; private _currentFileMatch: IFileMatch | null = null; constructor(private _onResult: (result: IFileMatch[]) => void) { diff --git a/src/vs/workbench/services/search/test/node/rawSearchService.test.ts b/src/vs/workbench/services/search/test/node/rawSearchService.test.ts index 68c517c3cf..99b87d8de3 100644 --- a/src/vs/workbench/services/search/test/node/rawSearchService.test.ts +++ b/src/vs/workbench/services/search/test/node/rawSearchService.test.ts @@ -185,6 +185,25 @@ suite('RawSearchService', () => { assert.strictEqual(result.results.length, 1, 'Result'); }); + test('Handles maxResults=0 correctly', async function () { + this.timeout(testTimeout); + const service = new RawSearchService(); + + const query: IFileQuery = { + type: QueryType.File, + folderQueries: MULTIROOT_QUERIES, + maxResults: 0, + sortByScore: true, + includePattern: { + '*.txt': true, + '*.js': true + }, + }; + + const result = await DiskSearch.collectResultsFromEvent(service.fileSearch(query)); + assert.strictEqual(result.results.length, 0, 'Result'); + }); + test('Multi-root with include pattern and exists', async function () { this.timeout(testTimeout); const service = new RawSearchService(); diff --git a/src/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts b/src/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts index 96713436e5..7dc1193808 100644 --- a/src/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts +++ b/src/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts @@ -17,9 +17,12 @@ suite('RipgrepTextSearchEngine', () => { assert.equal(unicodeEscapesToPCRE2('\\\\\\u1234'), '\\\\\\x{1234}'); assert.equal(unicodeEscapesToPCRE2('foo\\\\\\u1234'), 'foo\\\\\\x{1234}'); + assert.equal(unicodeEscapesToPCRE2('\\u{1234}'), '\\x{1234}'); + assert.equal(unicodeEscapesToPCRE2('\\u{1234}\\u{0001}'), '\\x{1234}\\x{0001}'); + assert.equal(unicodeEscapesToPCRE2('foo\\u{1234}bar'), 'foo\\x{1234}bar'); + + assert.equal(unicodeEscapesToPCRE2('foo\\u{123456}7bar'), 'foo\\u{123456}7bar'); assert.equal(unicodeEscapesToPCRE2('\\u123'), '\\u123'); - assert.equal(unicodeEscapesToPCRE2('\\u12345'), '\\u12345'); - assert.equal(unicodeEscapesToPCRE2('\\\\u12345'), '\\\\u12345'); assert.equal(unicodeEscapesToPCRE2('foo'), 'foo'); assert.equal(unicodeEscapesToPCRE2(''), ''); }); diff --git a/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts b/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts index e30e448957..f300ea3b2d 100644 --- a/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts +++ b/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts @@ -69,6 +69,26 @@ suite('Search-integration', function () { return doSearchTest(config, 4); }); + test('Text: GameOfLife (unicode escape sequences)', () => { + const config: ITextQuery = { + type: QueryType.Text, + folderQueries: ROOT_FOLDER_QUERY, + contentPattern: { pattern: 'G\\u{0061}m\\u0065OfLife', isRegExp: true } + }; + + return doSearchTest(config, 4); + }); + + test('Text: GameOfLife (unicode escape sequences, force PCRE2)', () => { + const config: ITextQuery = { + type: QueryType.Text, + folderQueries: ROOT_FOLDER_QUERY, + contentPattern: { pattern: '(? { const config: ITextQuery = { type: QueryType.Text, diff --git a/src/vs/workbench/services/telemetry/browser/telemetryService.ts b/src/vs/workbench/services/telemetry/browser/telemetryService.ts index 09590df331..f4e28399c1 100644 --- a/src/vs/workbench/services/telemetry/browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/browser/telemetryService.ts @@ -69,7 +69,7 @@ export class WebTelemetryAppender implements ITelemetryAppender { export class TelemetryService extends Disposable implements ITelemetryService { - _serviceBrand: any; + _serviceBrand: undefined; private impl: ITelemetryService; diff --git a/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts b/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts index 91e12fbf2f..04746c1296 100644 --- a/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts @@ -20,7 +20,7 @@ import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/pla export class TelemetryService extends Disposable implements ITelemetryService { - _serviceBrand: any; + _serviceBrand: undefined; private impl: ITelemetryService; @@ -38,7 +38,7 @@ export class TelemetryService extends Disposable implements ITelemetryService { const channel = sharedProcessService.getChannel('telemetryAppender'); const config: ITelemetryServiceConfig = { appender: combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(logService)), - commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.machineId, environmentService.installSourcePath, environmentService.configuration.remoteAuthority), + commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.machineId, productService.msftInternalDomains, environmentService.installSourcePath, environmentService.configuration.remoteAuthority), piiPaths: environmentService.extensionsPath ? [environmentService.appRoot, environmentService.extensionsPath] : [environmentService.appRoot] }; diff --git a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts index 6aef763790..e91cd7e531 100644 --- a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts +++ b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts @@ -31,7 +31,7 @@ import { IValidGrammarDefinition, IValidEmbeddedLanguagesMap, IValidTokenTypeMap import { TMGrammarFactory } from 'vs/workbench/services/textMate/common/TMGrammarFactory'; export abstract class AbstractTextMateService extends Disposable implements ITextMateService { - public _serviceBrand: any; + public _serviceBrand: undefined; private readonly _onDidEncounterLanguage: Emitter = this._register(new Emitter()); public readonly onDidEncounterLanguage: Event = this._onDidEncounterLanguage.event; @@ -203,36 +203,37 @@ export abstract class AbstractTextMateService extends Disposable implements ITex return this._grammarFactory; } - private async _registerDefinitionIfAvailable(modeId: string): Promise { + private _registerDefinitionIfAvailable(modeId: string): void { const languageIdentifier = this._modeService.getLanguageIdentifier(modeId); if (!languageIdentifier) { return; } - const languageId = languageIdentifier.id; - try { - if (!this._canCreateGrammarFactory()) { - return; - } - const grammarFactory = await this._getOrCreateGrammarFactory(); - if (grammarFactory.has(languageId)) { - const promise = grammarFactory.createGrammar(languageId).then((r) => { - const tokenization = new TMTokenization(r.grammar, r.initialState, r.containsEmbeddedLanguages); - tokenization.onDidEncounterLanguage((languageId) => { - if (!this._encounteredLanguages[languageId]) { - this._encounteredLanguages[languageId] = true; - this._onDidEncounterLanguage.fire(languageId); - } - }); - return new TMTokenizationSupport(r.languageId, tokenization, this._notificationService, this._configurationService, this._storageService); - }, e => { - onUnexpectedError(e); - return null; - }); - this._tokenizersRegistrations.push(TokenizationRegistry.registerPromise(modeId, promise)); - } - } catch (err) { - onUnexpectedError(err); + if (!this._canCreateGrammarFactory()) { + return; } + const languageId = languageIdentifier.id; + + // Here we must register the promise ASAP (without yielding!) + this._tokenizersRegistrations.push(TokenizationRegistry.registerPromise(modeId, (async () => { + try { + const grammarFactory = await this._getOrCreateGrammarFactory(); + if (!grammarFactory.has(languageId)) { + return null; + } + const r = await grammarFactory.createGrammar(languageId); + const tokenization = new TMTokenization(r.grammar, r.initialState, r.containsEmbeddedLanguages); + tokenization.onDidEncounterLanguage((languageId) => { + if (!this._encounteredLanguages[languageId]) { + this._encounteredLanguages[languageId] = true; + this._onDidEncounterLanguage.fire(languageId); + } + }); + return new TMTokenizationSupport(r.languageId, tokenization, this._notificationService, this._configurationService, this._storageService); + } catch (err) { + onUnexpectedError(err); + return null; + } + })())); } private static _toColorMap(colorMap: string[]): Color[] { diff --git a/src/vs/workbench/services/textMate/browser/textMateService.ts b/src/vs/workbench/services/textMate/browser/textMateService.ts index ed3864cdef..ebd30c8277 100644 --- a/src/vs/workbench/services/textMate/browser/textMateService.ts +++ b/src/vs/workbench/services/textMate/browser/textMateService.ts @@ -6,8 +6,7 @@ import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { AbstractTextMateService } from 'vs/workbench/services/textMate/browser/abstractTextMateService'; -import * as vscodeTextmate from 'vscode-textmate'; -import * as onigasm from 'onigasm-umd'; +import { IOnigLib } from 'vscode-textmate'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IFileService } from 'vs/platform/files/common/files'; import { ILogService } from 'vs/platform/log/common/log'; @@ -34,21 +33,25 @@ export class TextMateService extends AbstractTextMateService { return import('vscode-textmate'); } - protected _loadOnigLib(): Promise | undefined { + protected _loadOnigLib(): Promise | undefined { return loadOnigasm(); } } -let onigasmPromise: Promise | null = null; -async function loadOnigasm(): Promise { +let onigasmPromise: Promise | null = null; +async function loadOnigasm(): Promise { if (!onigasmPromise) { onigasmPromise = doLoadOnigasm(); } return onigasmPromise; } -async function doLoadOnigasm(): Promise { - const wasmBytes = await loadOnigasmWASM(); +async function doLoadOnigasm(): Promise { + const [wasmBytes, onigasm] = await Promise.all([ + loadOnigasmWASM(), + import('onigasm-umd') + ]); + await onigasm.loadWASM(wasmBytes); return { createOnigScanner(patterns: string[]) { return new onigasm.OnigScanner(patterns); }, diff --git a/src/vs/workbench/services/textMate/common/textMateService.ts b/src/vs/workbench/services/textMate/common/textMateService.ts index 5ba02e68b2..fb15c50272 100644 --- a/src/vs/workbench/services/textMate/common/textMateService.ts +++ b/src/vs/workbench/services/textMate/common/textMateService.ts @@ -10,7 +10,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export const ITextMateService = createDecorator('textMateService'); export interface ITextMateService { - _serviceBrand: any; + _serviceBrand: undefined; onDidEncounterLanguage: Event; diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index ca73a577c0..f555441133 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -22,7 +22,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel'; import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; -import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ResourceMap } from 'vs/base/common/map'; import { Schemas } from 'vs/base/common/network'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; @@ -46,7 +46,7 @@ import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; */ export abstract class TextFileService extends Disposable implements ITextFileService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private readonly _onAutoSaveConfigurationChange: Emitter = this._register(new Emitter()); readonly onAutoSaveConfigurationChange: Event = this._onAutoSaveConfigurationChange.event; @@ -158,9 +158,8 @@ export abstract class TextFileService extends Disposable implements ITextFileSer // since a backup did not happen, we have to confirm for the dirty files now return this.confirmBeforeShutdown(); - }, errors => { - const firstError = errors[0]; - this.notificationService.error(nls.localize('files.backup.failSave', "Files that are dirty could not be written to the backup location (Error: {0}). Try saving your files first and then exit.", firstError.message)); + }, error => { + this.notificationService.error(nls.localize('files.backup.failSave', "Files that are dirty could not be written to the backup location (Error: {0}). Try saving your files first and then exit.", error.message)); return true; // veto, the backups failed }); @@ -589,12 +588,12 @@ export abstract class TextFileService extends Disposable implements ITextFileSer nls.localize('cancel', "Cancel") ]; - const index = await this.dialogService.show(Severity.Warning, message, buttons, { + const { choice } = await this.dialogService.show(Severity.Warning, message, buttons, { cancelId: 2, detail: nls.localize('saveChangesDetail', "Your changes will be lost if you don't save them.") }); - switch (index) { + switch (choice) { case 0: return ConfirmResult.SAVE; case 1: return ConfirmResult.DONT_SAVE; default: return ConfirmResult.CANCEL; diff --git a/src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts b/src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts index ead7803006..2fd4ef389d 100644 --- a/src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts +++ b/src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts @@ -13,11 +13,10 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class TextResourcePropertiesService implements ITextResourcePropertiesService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private remoteEnvironment: IRemoteAgentEnvironment | null = null; diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index 06a787db61..a4e74da7be 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -8,7 +8,7 @@ import { Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IEncodingSupport, ConfirmResult, IRevertOptions, IModeSupport } from 'vs/workbench/common/editor'; import { IBaseStatWithMetadata, IFileStatWithMetadata, IReadFileOptions, IWriteFileOptions, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ITextEditorModel } from 'vs/editor/common/services/resolverService'; import { ITextBufferFactory, ITextModel, ITextSnapshot } from 'vs/editor/common/model'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -19,7 +19,7 @@ export const ITextFileService = createDecorator('textFileServi export interface ITextFileService extends IDisposable { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; readonly onWillMove: Event; @@ -253,7 +253,7 @@ export const enum ModelState { PENDING_SAVE, /** - * A model is marked for being saved after a specific timeout. + * A model is marked for being saved after a specific timeout. */ PENDING_AUTO_SAVE, diff --git a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts index 987f060544..e824bcf627 100644 --- a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts +++ b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts @@ -121,7 +121,7 @@ class ResourceModelCollection extends ReferenceCollection(JSONExtensions.JSONContribution); schemaRegistry.registerSchema(schemaId, schema); -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/themes/common/workbenchThemeService.ts b/src/vs/workbench/services/themes/common/workbenchThemeService.ts index aeccfd9c22..00451491f4 100644 --- a/src/vs/workbench/services/themes/common/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/common/workbenchThemeService.ts @@ -51,7 +51,7 @@ export interface IFileIconTheme extends IIconTheme { } export interface IWorkbenchThemeService extends IThemeService { - _serviceBrand: any; + _serviceBrand: undefined; setColorTheme(themeId: string | undefined, settingsTarget: ConfigurationTarget | undefined): Promise; getColorTheme(): IColorTheme; getColorThemes(): Promise; diff --git a/src/vs/workbench/services/timer/electron-browser/timerService.ts b/src/vs/workbench/services/timer/electron-browser/timerService.ts index 28a64511de..a7e48a7dde 100644 --- a/src/vs/workbench/services/timer/electron-browser/timerService.ts +++ b/src/vs/workbench/services/timer/electron-browser/timerService.ts @@ -297,13 +297,13 @@ export interface IStartupMetrics { } export interface ITimerService { - _serviceBrand: any; + _serviceBrand: undefined; readonly startupMetrics: Promise; } class TimerService implements ITimerService { - _serviceBrand: any; + _serviceBrand: undefined; private _startupMetrics?: Promise; diff --git a/src/vs/workbench/services/title/common/titleService.ts b/src/vs/workbench/services/title/common/titleService.ts index f0acf4d2ba..88e905c9a3 100644 --- a/src/vs/workbench/services/title/common/titleService.ts +++ b/src/vs/workbench/services/title/common/titleService.ts @@ -14,7 +14,7 @@ export interface ITitleProperties { } export interface ITitleService { - _serviceBrand: any; + _serviceBrand: undefined; /** * An event when the menubar visibility changes. diff --git a/src/vs/workbench/services/untitled/common/untitledEditorService.ts b/src/vs/workbench/services/untitled/common/untitledEditorService.ts index c85fca9248..118707c389 100644 --- a/src/vs/workbench/services/untitled/common/untitledEditorService.ts +++ b/src/vs/workbench/services/untitled/common/untitledEditorService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { createDecorator, IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import * as arrays from 'vs/base/common/arrays'; import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput'; import { IFilesConfiguration, IFileService } from 'vs/platform/files/common/files'; @@ -29,7 +29,7 @@ export interface IModelLoadOrCreateOptions { export interface IUntitledEditorService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; /** * Events for when untitled editors content changes (e.g. any keystroke). @@ -112,7 +112,7 @@ export interface IUntitledEditorService { export class UntitledEditorService extends Disposable implements IUntitledEditorService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; private mapResourceToInput = new ResourceMap(); private mapResourceToAssociatedFilePath = new ResourceMap(); diff --git a/src/vs/workbench/services/update/browser/updateService.ts b/src/vs/workbench/services/update/browser/updateService.ts new file mode 100644 index 0000000000..b1fe90e03a --- /dev/null +++ b/src/vs/workbench/services/update/browser/updateService.ts @@ -0,0 +1,95 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Event, Emitter } from 'vs/base/common/event'; +import { IUpdateService, State, UpdateType } from 'vs/platform/update/common/update'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IWindowService } from 'vs/platform/windows/common/windows'; +import { Disposable } from 'vs/base/common/lifecycle'; + +export interface IUpdate { + version: string; +} + +export interface IUpdateProvider { + + /** + * Should return with the `IUpdate` object if an update is + * available or `null` otherwise to signal that there are + * no updates. + */ + checkForUpdate(): Promise; +} + +export class UpdateService extends Disposable implements IUpdateService { + + _serviceBrand: undefined; + + private _onStateChange = this._register(new Emitter()); + readonly onStateChange: Event = this._onStateChange.event; + + private _state: State = State.Uninitialized; + get state(): State { return this._state; } + set state(state: State) { + this._state = state; + this._onStateChange.fire(state); + } + + constructor( + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IWindowService private readonly windowService: IWindowService + ) { + super(); + + this.checkForUpdates(); + } + + async isLatestVersion(): Promise { + const update = await this.doCheckForUpdates(); + + return !!update; + } + + async checkForUpdates(): Promise { + await this.doCheckForUpdates(); + } + + private async doCheckForUpdates(): Promise { + if (this.environmentService.options && this.environmentService.options.updateProvider) { + const updateProvider = this.environmentService.options.updateProvider; + + // State -> Checking for Updates + this.state = State.CheckingForUpdates(null); + + const update = await updateProvider.checkForUpdate(); + if (update) { + // State -> Downloaded + this.state = State.Ready({ version: update.version, productVersion: update.version }); + } else { + // State -> Idle + this.state = State.Idle(UpdateType.Archive); + } + + return update; + } + + return null; // no update provider to ask + } + + async downloadUpdate(): Promise { + // no-op + } + + async applyUpdate(): Promise { + this.windowService.reloadWindow(); + } + + async quitAndInstall(): Promise { + this.windowService.reloadWindow(); + } +} + +registerSingleton(IUpdateService, UpdateService); diff --git a/src/vs/workbench/services/url/browser/urlService.ts b/src/vs/workbench/services/url/browser/urlService.ts index 05399205cb..a2c8647c95 100644 --- a/src/vs/workbench/services/url/browser/urlService.ts +++ b/src/vs/workbench/services/url/browser/urlService.ts @@ -5,17 +5,10 @@ import { IURLService } from 'vs/platform/url/common/url'; import { URI, UriComponents } from 'vs/base/common/uri'; -import { ServiceIdentifier, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { AbstractURLService } from 'vs/platform/url/common/urlService'; -import { Event, Emitter } from 'vs/base/common/event'; +import { Event } from 'vs/base/common/event'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { IRequestService } from 'vs/platform/request/common/request'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { streamToBuffer } from 'vs/base/common/buffer'; -import { ILogService } from 'vs/platform/log/common/log'; -import { generateUuid } from 'vs/base/common/uuid'; export interface IURLCallbackProvider { @@ -45,132 +38,32 @@ export interface IURLCallbackProvider { export class BrowserURLService extends AbstractURLService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; - private provider: IURLCallbackProvider; + private provider: IURLCallbackProvider | undefined; constructor( - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IInstantiationService instantiationService: IInstantiationService + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService ) { super(); - this.provider = environmentService.options && environmentService.options.urlCallbackProvider ? environmentService.options.urlCallbackProvider : instantiationService.createInstance(SelfhostURLCallbackProvider); + this.provider = environmentService.options!.urlCallbackProvider; this.registerListeners(); } private registerListeners(): void { - this._register(this.provider.onCallback(uri => this.open(uri))); + if (this.provider) { + this._register(this.provider.onCallback(uri => this.open(uri))); + } } create(options?: Partial): URI { - return this.provider.create(options); - } -} - -class SelfhostURLCallbackProvider extends Disposable implements IURLCallbackProvider { - - static FETCH_INTERVAL = 500; // fetch every 500ms - static FETCH_TIMEOUT = 5 * 60 * 1000; // ...but stop after 5min - - static QUERY_KEYS = { - REQUEST_ID: 'vscode-requestId', - SCHEME: 'vscode-scheme', - AUTHORITY: 'vscode-authority', - PATH: 'vscode-path', - QUERY: 'vscode-query', - FRAGMENT: 'vscode-fragment' - }; - - private readonly _onCallback: Emitter = this._register(new Emitter()); - readonly onCallback: Event = this._onCallback.event; - - constructor( - @IRequestService private readonly requestService: IRequestService, - @ILogService private readonly logService: ILogService - ) { - super(); - } - - create(options?: Partial): URI { - const queryValues: Map = new Map(); - - const requestId = generateUuid(); - queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.REQUEST_ID, requestId); - - const { scheme, authority, path, query, fragment } = options ? options : { scheme: undefined, authority: undefined, path: undefined, query: undefined, fragment: undefined }; - - if (scheme) { - queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.SCHEME, scheme); + if (this.provider) { + return this.provider.create(options); } - if (authority) { - queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.AUTHORITY, authority); - } - - if (path) { - queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.PATH, path); - } - - if (query) { - queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.QUERY, query); - } - - if (fragment) { - queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.FRAGMENT, fragment); - } - - // Start to poll on the callback being fired - this.periodicFetchCallback(requestId, Date.now()); - - return this.doCreateUri('/callback', queryValues); - } - - private async periodicFetchCallback(requestId: string, startTime: number): Promise { - - // Ask server for callback results - const queryValues: Map = new Map(); - queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.REQUEST_ID, requestId); - - const result = await this.requestService.request({ - url: this.doCreateUri('/fetch-callback', queryValues).toString(true) - }, CancellationToken.None); - - // Check for callback results - const content = await streamToBuffer(result.stream); - if (content.byteLength > 0) { - try { - this._onCallback.fire(URI.revive(JSON.parse(content.toString()))); - } catch (error) { - this.logService.error(error); - } - - return; // done - } - - // Continue fetching unless we hit the timeout - if (Date.now() - startTime < SelfhostURLCallbackProvider.FETCH_TIMEOUT) { - setTimeout(() => this.periodicFetchCallback(requestId, startTime), SelfhostURLCallbackProvider.FETCH_INTERVAL); - } - } - - private doCreateUri(path: string, queryValues: Map): URI { - let query: string | undefined = undefined; - - if (queryValues) { - let index = 0; - queryValues.forEach((value, key) => { - if (!query) { - query = ''; - } - - const prefix = (index++ === 0) ? '' : '&'; - query += `${prefix}${key}=${encodeURIComponent(value)}`; - }); - } - - return URI.parse(window.location.href).with({ path, query }); + return URI.parse('unsupported://'); } } diff --git a/src/vs/workbench/services/url/electron-browser/urlService.ts b/src/vs/workbench/services/url/electron-browser/urlService.ts index bbf124801d..5130f7d307 100644 --- a/src/vs/workbench/services/url/electron-browser/urlService.ts +++ b/src/vs/workbench/services/url/electron-browser/urlService.ts @@ -4,13 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; -import { URI } from 'vs/base/common/uri'; +import { URI, UriComponents } from 'vs/base/common/uri'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; -import { URLServiceChannelClient, URLHandlerChannel } from 'vs/platform/url/node/urlIpc'; +import { URLServiceChannelClient, URLHandlerChannel } from 'vs/platform/url/common/urlIpc'; import { URLService } from 'vs/platform/url/node/urlService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import product from 'vs/platform/product/node/product'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IWindowService } from 'vs/platform/windows/common/windows'; export class RelayURLService extends URLService implements IURLHandler { @@ -18,7 +19,8 @@ export class RelayURLService extends URLService implements IURLHandler { constructor( @IMainProcessService mainProcessService: IMainProcessService, - @IOpenerService openerService: IOpenerService + @IOpenerService openerService: IOpenerService, + @IWindowService private windowService: IWindowService ) { super(); @@ -28,11 +30,20 @@ export class RelayURLService extends URLService implements IURLHandler { openerService.registerOpener(this); } - async open(resource: URI, options?: { openToSide?: boolean, openExternal?: boolean }): Promise { - if (options && options.openExternal) { - return false; + create(options?: Partial): URI { + const uri = super.create(options); + + let query = uri.query; + if (!query) { + query = `windowId=${encodeURIComponent(this.windowService.windowId)}`; + } else { + query += `&windowId=${encodeURIComponent(this.windowService.windowId)}`; } + return uri.with({ query }); + } + + async open(resource: URI, options?: { openToSide?: boolean, openExternal?: boolean }): Promise { if (resource.scheme !== product.urlProtocol) { return false; } diff --git a/src/vs/workbench/services/viewlet/browser/viewlet.ts b/src/vs/workbench/services/viewlet/browser/viewlet.ts index 2684916550..be2d2f2d20 100644 --- a/src/vs/workbench/services/viewlet/browser/viewlet.ts +++ b/src/vs/workbench/services/viewlet/browser/viewlet.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IViewlet } from 'vs/workbench/common/viewlet'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { IProgressIndicator } from 'vs/platform/progress/common/progress'; @@ -13,7 +13,7 @@ export const IViewletService = createDecorator('viewletService' export interface IViewletService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; readonly onDidViewletRegister: Event; readonly onDidViewletDeregister: Event; diff --git a/src/vs/workbench/services/window/electron-browser/windowService.ts b/src/vs/workbench/services/window/electron-browser/windowService.ts index 1f05a6c6f7..c62f97a26c 100644 --- a/src/vs/workbench/services/window/electron-browser/windowService.ts +++ b/src/vs/workbench/services/window/electron-browser/windowService.ts @@ -19,7 +19,7 @@ export class WindowService extends Disposable implements IWindowService { readonly onDidChangeFocus: Event; readonly onDidChangeMaximize: Event; - _serviceBrand: any; + _serviceBrand: undefined; private _windowId: number; private remoteAuthority: string | undefined; diff --git a/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts b/src/vs/workbench/services/workspace/browser/workspaceEditingService.ts similarity index 96% rename from src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts rename to src/vs/workbench/services/workspace/browser/workspaceEditingService.ts index 679b874d12..855e4a4312 100644 --- a/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/browser/workspaceEditingService.ts @@ -12,7 +12,6 @@ import { IJSONEditingService, JSONEditingError, JSONEditingErrorCode } from 'vs/ import { IWorkspaceIdentifier, IWorkspaceFolderCreationData, IWorkspacesService, rewriteWorkspaceFileForNewLocation, WORKSPACE_FILTER } from 'vs/platform/workspaces/common/workspaces'; import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { StorageService } from 'vs/platform/storage/node/storageService'; import { ConfigurationScope, IConfigurationRegistry, Extensions as ConfigurationExtensions, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -20,7 +19,7 @@ import { IBackupFileService, toBackupWorkspaceResource } from 'vs/workbench/serv import { BackupFileService } from 'vs/workbench/services/backup/common/backupFileService'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { distinct } from 'vs/base/common/arrays'; -import { isLinux, isWindows, isMacintosh } from 'vs/base/common/platform'; +import { isLinux, isWindows, isMacintosh, isWeb } from 'vs/base/common/platform'; import { isEqual, basename, isEqualOrParent, getComparisonKey } from 'vs/base/common/resources'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IFileService } from 'vs/platform/files/common/files'; @@ -32,11 +31,10 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILabelService } from 'vs/platform/label/common/label'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class WorkspaceEditingService implements IWorkspaceEditingService { - _serviceBrand!: ServiceIdentifier; + _serviceBrand: undefined; constructor( @IJSONEditingService private readonly jsonEditingService: IJSONEditingService, @@ -62,7 +60,11 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { } private registerListeners(): void { - this.lifecycleService.onBeforeShutdown(async e => { + this.lifecycleService.onBeforeShutdown(e => { + if (isWeb) { + return; // no support for untitled in web + } + const saveOperation = this.saveUntitedBeforeShutdown(e.reason); if (saveOperation) { e.veto(saveOperation); @@ -109,9 +111,9 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { const detail = nls.localize('saveWorkspaceDetail', "Save your workspace if you plan to open it again."); const cancelId = buttons.indexOf(cancel); - const res = await this.dialogService.show(Severity.Warning, message, buttons.map(button => button.label), { detail, cancelId }); + const { choice } = await this.dialogService.show(Severity.Warning, message, buttons.map(button => button.label), { detail, cancelId }); - switch (buttons[res].result) { + switch (buttons[choice].result) { // Cancel: veto unload case ConfirmResult.CANCEL: @@ -422,9 +424,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { } private migrateStorage(toWorkspace: IWorkspaceIdentifier): Promise { - const storageImpl = this.storageService as StorageService; - - return storageImpl.migrate(toWorkspace); + return this.storageService.migrate(toWorkspace); } private migrateWorkspaceSettings(toWorkspace: IWorkspaceIdentifier): Promise { diff --git a/src/vs/workbench/services/workspace/common/workspaceEditing.ts b/src/vs/workbench/services/workspace/common/workspaceEditing.ts index d198672ed0..f2fd98d196 100644 --- a/src/vs/workbench/services/workspace/common/workspaceEditing.ts +++ b/src/vs/workbench/services/workspace/common/workspaceEditing.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IWorkspaceIdentifier, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; import { URI } from 'vs/base/common/uri'; @@ -11,7 +11,7 @@ export const IWorkspaceEditingService = createDecorator; + _serviceBrand: undefined; /** * Add folders to the existing workspace. @@ -56,4 +56,4 @@ export interface IWorkspaceEditingService { * picks a new workspace path */ pickNewWorkspacePath(): Promise; -} \ No newline at end of file +} diff --git a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts index ae67eb8b4c..3f30fa6bab 100644 --- a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts @@ -300,4 +300,4 @@ suite('Workbench base editor', () => { MyEditor: MyEditor, MyOtherEditor: MyOtherEditor }; -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/test/browser/quickopen.test.ts b/src/vs/workbench/test/browser/quickopen.test.ts index 5f97e34c96..5a412ad3ba 100644 --- a/src/vs/workbench/test/browser/quickopen.test.ts +++ b/src/vs/workbench/test/browser/quickopen.test.ts @@ -11,7 +11,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenAction, QuickOpenHandler } from 'vs/workbench/browser/quickopen'; export class TestQuickOpenService implements IQuickOpenService { - public _serviceBrand: any; + public _serviceBrand: undefined; private callback?: (prefix?: string) => void; diff --git a/src/vs/workbench/test/contrib/linkProtection.test.ts b/src/vs/workbench/test/contrib/linkProtection.test.ts new file mode 100644 index 0000000000..77e4076ac9 --- /dev/null +++ b/src/vs/workbench/test/contrib/linkProtection.test.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { isURLDomainTrusted } from 'vs/workbench/contrib/url/common/url.contribution'; +import { URI } from 'vs/base/common/uri'; + +suite('Link protection domain matching', () => { + + test('simple', () => { + assert.ok(!isURLDomainTrusted(URI.parse('https://x.org'), [])); + assert.ok(isURLDomainTrusted(URI.parse('https://x.org'), ['https://x.org'])); + assert.ok(isURLDomainTrusted(URI.parse('https://x.org/foo'), ['https://x.org'])); + + assert.ok(!isURLDomainTrusted(URI.parse('https://x.org'), ['http://x.org'])); + assert.ok(!isURLDomainTrusted(URI.parse('http://x.org'), ['https://x.org'])); + + assert.ok(!isURLDomainTrusted(URI.parse('https://www.x.org'), ['https://x.org'])); + + assert.ok(isURLDomainTrusted(URI.parse('https://www.x.org'), ['https://www.x.org', 'https://y.org'])); + }); + + test('localhost', () => { + assert.ok(isURLDomainTrusted(URI.parse('https://127.0.0.1'), [])); + assert.ok(isURLDomainTrusted(URI.parse('https://127.0.0.1:3000'), [])); + assert.ok(isURLDomainTrusted(URI.parse('https://localhost'), [])); + assert.ok(isURLDomainTrusted(URI.parse('https://localhost:3000'), [])); + }); + + test('* star', () => { + assert.ok(isURLDomainTrusted(URI.parse('https://a.x.org'), ['https://*.x.org'])); + assert.ok(isURLDomainTrusted(URI.parse('https://a.x.org'), ['https://a.x.*'])); + assert.ok(isURLDomainTrusted(URI.parse('https://a.x.org'), ['https://a.*.org'])); + assert.ok(isURLDomainTrusted(URI.parse('https://a.x.org'), ['https://*.*.org'])); + + assert.ok(!isURLDomainTrusted(URI.parse('https://a.b.c.org'), ['https://*.*.org'])); + assert.ok(isURLDomainTrusted(URI.parse('https://a.b.c.org'), ['https://*.*.*.org'])); + }); +}); diff --git a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts index a76783fc0d..a8f41de893 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts @@ -78,7 +78,7 @@ suite('ExtHostLanguageFeatureCommands', function () { }); instantiationService.stub(IMarkerService, new MarkerService()); instantiationService.stub(IModelService, { - _serviceBrand: IModelService, + _serviceBrand: undefined, getModel(): any { return model; }, createModel() { throw new Error(); }, updateModel() { throw new Error(); }, @@ -857,4 +857,33 @@ suite('ExtHostLanguageFeatureCommands', function () { assert.ok(value[0].parent); }); + // --- call hierarcht + + test('Call Hierarchy, back and forth', async function () { + + disposables.push(extHost.registerCallHierarchyProvider(nullExtensionDescription, defaultSelector, new class implements vscode.CallHierarchyItemProvider { + provideCallHierarchyIncomingCalls(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.ProviderResult { + return [ + new types.CallHierarchyIncomingCall(new types.CallHierarchyItem(types.SymbolKind.Array, 'IN', '', document.uri, new types.Range(0, 0, 2, 0), new types.Range(0, 0, 2, 0)), [new types.Range(0, 0, 0, 0)]), + ]; + } + provideCallHierarchyOutgoingCalls(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.ProviderResult { + return [ + new types.CallHierarchyOutgoingCall(new types.CallHierarchyItem(types.SymbolKind.Array, 'OUT', '', document.uri, new types.Range(0, 0, 2, 0), new types.Range(0, 0, 2, 0)), [new types.Range(0, 0, 0, 0)]), + ]; + } + })); + + await rpcProtocol.sync(); + + let incoming = await commands.executeCommand('vscode.executeCallHierarchyProviderIncomingCalls', model.uri, new types.Position(0, 10)); + assert.equal(incoming.length, 1); + assert.ok(incoming[0].source instanceof types.CallHierarchyItem); + assert.equal(incoming[0].source.name, 'IN'); + + let outgoing = await commands.executeCommand('vscode.executeCallHierarchyProviderOutgoingCalls', model.uri, new types.Position(0, 10)); + assert.equal(outgoing.length, 1); + assert.ok(outgoing[0].target instanceof types.CallHierarchyItem); + assert.equal(outgoing[0].target.name, 'OUT'); + }); }); diff --git a/src/vs/workbench/test/electron-browser/api/extHostCommands.test.ts b/src/vs/workbench/test/electron-browser/api/extHostCommands.test.ts index f8536d932d..aae54020da 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostCommands.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostCommands.test.ts @@ -59,4 +59,35 @@ suite('ExtHostCommands', function () { reg.dispose(); assert.equal(unregisterCounter, 1); }); + + test('execute with retry', async function () { + + let count = 0; + + const shape = new class extends mock() { + $registerCommand(id: string): void { + // + } + async $executeCommand(id: string, args: any[], retry: boolean): Promise { + count++; + assert.equal(retry, count === 1); + if (count === 1) { + assert.equal(retry, true); + throw new Error('$executeCommand:retry'); + } else { + assert.equal(retry, false); + return 17; + } + } + }; + + const commands = new ExtHostCommands( + SingleProxyRPCProtocol(shape), + new NullLogService() + ); + + const result = await commands.executeCommand('fooo', [this, true]); + assert.equal(result, 17); + assert.equal(count, 2); + }); }); 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 40c7ffb554..24bb5ec4c7 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts @@ -9,11 +9,10 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService, INotification, NoOpNotification, INotificationHandle, Severity, IPromptChoice, IPromptOptions, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; const emptyDialogService = new class implements IDialogService { - _serviceBrand: 'dialogService'; + _serviceBrand: undefined; show(): never { throw new Error('not implemented'); } @@ -33,7 +32,7 @@ const emptyCommandService: ICommandService = { }; const emptyNotificationService = new class implements INotificationService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; notify(...args: any[]): never { throw new Error('not implemented'); } @@ -55,7 +54,7 @@ const emptyNotificationService = new class implements INotificationService { }; class EmptyNotificationService implements INotificationService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; constructor(private withNotify: (notification: INotification) => void) { } @@ -103,7 +102,7 @@ suite('ExtHostMessageService', function () { assert.equal(message, 'h'); assert.equal(buttons.length, 2); assert.equal(buttons[1], 'Cancel'); - return Promise.resolve(0); + return Promise.resolve({ choice: 0 }); } } as IDialogService); @@ -114,7 +113,7 @@ suite('ExtHostMessageService', function () { test('returns undefined when cancelled', async () => { const service = new MainThreadMessageService(null!, emptyNotificationService, emptyCommandService, new class extends mock() { show() { - return Promise.resolve(1); + return Promise.resolve({ choice: 1 }); } } as IDialogService); @@ -126,7 +125,7 @@ suite('ExtHostMessageService', function () { const service = new MainThreadMessageService(null!, emptyNotificationService, emptyCommandService, new class extends mock() { show(severity: Severity, message: string, buttons: string[]) { assert.equal(buttons.length, 1); - return Promise.resolve(0); + return Promise.resolve({ choice: 0 }); } } as IDialogService); diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadCommands.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadCommands.test.ts index 937aee6244..09d5b99b8e 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadCommands.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadCommands.test.ts @@ -5,14 +5,16 @@ import * as assert from 'assert'; import { MainThreadCommands } from 'vs/workbench/api/browser/mainThreadCommands'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; import { SingleProxyRPCProtocol } from './testRPCProtocol'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { mock } from 'vs/workbench/test/electron-browser/api/mock'; suite('MainThreadCommands', function () { test('dispose on unregister', function () { - const commands = new MainThreadCommands(SingleProxyRPCProtocol(null), undefined!); + const commands = new MainThreadCommands(SingleProxyRPCProtocol(null), undefined!, new class extends mock() { }); assert.equal(CommandsRegistry.getCommand('foo'), undefined); // register @@ -26,7 +28,7 @@ suite('MainThreadCommands', function () { test('unregister all on dispose', function () { - const commands = new MainThreadCommands(SingleProxyRPCProtocol(null), undefined!); + const commands = new MainThreadCommands(SingleProxyRPCProtocol(null), undefined!, new class extends mock() { }); assert.equal(CommandsRegistry.getCommand('foo'), undefined); commands.$registerCommand('foo'); @@ -40,4 +42,46 @@ suite('MainThreadCommands', function () { assert.equal(CommandsRegistry.getCommand('foo'), undefined); assert.equal(CommandsRegistry.getCommand('bar'), undefined); }); + + test('activate and throw when needed', async function () { + + const activations: string[] = []; + const runs: string[] = []; + + const commands = new MainThreadCommands( + SingleProxyRPCProtocol(null), + new class extends mock() { + executeCommand(id: string): Promise { + runs.push(id); + return Promise.resolve(undefined); + } + }, + new class extends mock() { + activateByEvent(id: string) { + activations.push(id); + return Promise.resolve(); + } + } + ); + + // case 1: arguments and retry + try { + activations.length = 0; + await commands.$executeCommand('bazz', [1, 2, { n: 3 }], true); + assert.ok(false); + } catch (e) { + assert.deepEqual(activations, ['onCommand:bazz']); + assert.equal((e).message, '$executeCommand:retry'); + } + + // case 2: no arguments and retry + runs.length = 0; + await commands.$executeCommand('bazz', [], true); + assert.deepEqual(runs, ['bazz']); + + // case 3: arguments and no retry + runs.length = 0; + await commands.$executeCommand('bazz', [1, 2, true], false); + assert.deepEqual(runs, ['bazz']); + }); }); diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts index 8634fbbde0..7f9913044b 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts @@ -75,7 +75,7 @@ suite('MainThreadDocumentsAndEditors', () => { editorGroupService, null!, new class extends mock() implements IPanelService { - _serviceBrand: any; + _serviceBrand: undefined; onDidPanelOpen = Event.None; onDidPanelClose = Event.None; getActivePanel() { diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts index 532131bc72..c7ab29204b 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts @@ -107,7 +107,7 @@ suite('MainThreadEditors', () => { editorGroupService, bulkEditService, new class extends mock() implements IPanelService { - _serviceBrand: any; + _serviceBrand: undefined; onDidPanelOpen = Event.None; onDidPanelClose = Event.None; getActivePanel() { diff --git a/src/vs/workbench/test/electron-browser/api/testRPCProtocol.ts b/src/vs/workbench/test/electron-browser/api/testRPCProtocol.ts index 3f876deaea..47154800c6 100644 --- a/src/vs/workbench/test/electron-browser/api/testRPCProtocol.ts +++ b/src/vs/workbench/test/electron-browser/api/testRPCProtocol.ts @@ -25,7 +25,7 @@ export function SingleProxyRPCProtocol(thing: any): IExtHostContext & IExtHostRp export class TestRPCProtocol implements IExtHostContext, IExtHostRpcService { - public _serviceBrand = undefined; + public _serviceBrand: undefined; public remoteAuthority = null!; private _callCountValue: number = 0; diff --git a/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts b/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts index dd1efa6423..80eb0c7f6e 100644 --- a/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts +++ b/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts @@ -5,13 +5,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IColorRegistry, Extensions, ColorContribution } from 'vs/platform/theme/common/colorRegistry'; -import { editorMarkerNavigationError } from 'vs/editor/contrib/gotoError/gotoErrorWidget'; -import { overviewRulerModifiedForeground } from 'vs/workbench/contrib/scm/browser/dirtydiffDecorator'; -import { STATUS_BAR_DEBUGGING_BACKGROUND } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider'; -import { debugExceptionWidgetBackground } from 'vs/workbench/contrib/debug/browser/exceptionWidget'; -import { debugToolBarBackground } from 'vs/workbench/contrib/debug/browser/debugToolBar'; -import { buttonBackground } from 'vs/workbench/contrib/welcome/page/browser/welcomePage'; -import { embeddedEditorBackground } from 'vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart'; + import { asText } from 'vs/platform/request/common/request'; import * as pfs from 'vs/base/node/pfs'; import * as path from 'vs/base/common/path'; @@ -20,6 +14,7 @@ import { getPathFromAmdModule } from 'vs/base/common/amd'; import { CancellationToken } from 'vs/base/common/cancellation'; import { RequestService } from 'vs/platform/request/node/requestService'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import 'vs/workbench/workbench.desktop.main'; import { NullLogService } from 'vs/platform/log/common/log'; @@ -34,25 +29,25 @@ interface DescriptionDiff { specDescription: string; } -// add artificial dependencies to some files that are not loaded yet -export const forceColorLoad = [editorMarkerNavigationError, overviewRulerModifiedForeground, STATUS_BAR_DEBUGGING_BACKGROUND, - debugExceptionWidgetBackground, debugToolBarBackground, buttonBackground, embeddedEditorBackground]; - export const experimental: string[] = []; // 'settings.modifiedItemForeground', 'editorUnnecessary.foreground' ]; suite('Color Registry', function () { - test('all colors documented', async function () { - const reqContext = await new RequestService(new TestConfigurationService(), new NullLogService()).request({ url: 'https://raw.githubusercontent.com/Microsoft/vscode-docs/vnext/docs/getstarted/theme-color-reference.md' }, CancellationToken.None); + test('all colors documented in theme-color.md', async function () { + const reqContext = await new RequestService(new TestConfigurationService(), new NullLogService()).request({ url: 'https://raw.githubusercontent.com/microsoft/vscode-docs/vnext/api/references/theme-color.md' }, CancellationToken.None); const content = (await asText(reqContext))!; const expression = /\-\s*\`([\w\.]+)\`: (.*)/g; let m: RegExpExecArray | null; let colorsInDoc: { [id: string]: ColorInfo } = Object.create(null); + let nColorsInDoc = 0; while (m = expression.exec(content)) { colorsInDoc[m[1]] = { description: m[2], offset: m.index, length: m.length }; + nColorsInDoc++; } + assert.ok(nColorsInDoc > 0, 'theme-color.md contains to color descriptions'); + let missing = Object.create(null); let descriptionDiffs: { [id: string]: DescriptionDiff } = Object.create(null); @@ -88,7 +83,7 @@ suite('Color Registry', function () { } } - let undocumentedKeys = Object.keys(missing).map(k => `${k}: ${missing[k]}`); + let undocumentedKeys = Object.keys(missing).map(k => `\`${k}\`: ${missing[k]}`); assert.deepEqual(undocumentedKeys, [], 'Undocumented colors ids'); let superfluousKeys = Object.keys(colorsInDoc); @@ -106,7 +101,7 @@ function getDescription(color: ColorContribution) { } async function getColorsFromExtension(): Promise<{ [id: string]: string }> { - let extPath = getPathFromAmdModule(require, '../../../../../../extensions'); + let extPath = getPathFromAmdModule(require, '../../../../../extensions'); let extFolders = await pfs.readDirsInDir(extPath); let result: { [id: string]: string } = Object.create(null); for (let folder of extFolders) { diff --git a/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts b/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts index 6c7d354742..0deb0cf40a 100644 --- a/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts +++ b/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts @@ -160,7 +160,7 @@ suite.skip('QuickOpen performance (integration)', () => { class TestTelemetryService implements ITelemetryService { - public _serviceBrand: any; + public _serviceBrand: undefined; public isOptedIn = true; public events: any[] = []; diff --git a/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts b/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts index 17ccae608e..fe8a3099f3 100644 --- a/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts +++ b/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts @@ -145,7 +145,7 @@ suite.skip('TextSearch performance (integration)', () => { }); class TestTelemetryService implements ITelemetryService { - public _serviceBrand: any; + public _serviceBrand: undefined; public isOptedIn = true; public events: any[] = []; diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index b58504822c..8d87c7a3c4 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -30,10 +30,10 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { ITextFileStreamContent, ITextFileService, IResourceEncoding, IReadTextFileOptions } from 'vs/workbench/services/textfile/common/textfiles'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { IInstantiationService, ServicesAccessor, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { IWindowsService, IWindowService, INativeOpenDialogOptions, IEnterWorkspaceResult, IMessageBoxResult, MenuBarVisibility, IURIToOpen, IOpenSettings, IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; @@ -50,7 +50,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { MockContextKeyService, MockKeybindingService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; import { ITextBufferFactory, DefaultEndOfLine, EndOfLinePreference, IModelDecorationOptions, ITextModel, ITextSnapshot } from 'vs/editor/common/model'; import { Range } from 'vs/editor/common/core/range'; -import { IConfirmation, IConfirmationResult, IDialogService, IDialogOptions, IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IConfirmation, IConfirmationResult, IDialogService, IDialogOptions, IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, IFileDialogService, IShowResult } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; import { IExtensionService, NullExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -91,10 +91,10 @@ export function createFileInput(instantiationService: IInstantiationService, res return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined); } -export const TestEnvironmentService = new WorkbenchEnvironmentService(parseArgs(process.argv) as IWindowConfiguration, process.execPath); +export const TestEnvironmentService = new WorkbenchEnvironmentService(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath); export class TestContextService implements IWorkspaceContextService { - public _serviceBrand: any; + public _serviceBrand: undefined; private workspace: Workspace; private options: any; @@ -106,6 +106,7 @@ export class TestContextService implements IWorkspaceContextService { constructor(workspace: any = TestWorkspace, options: any = null) { this.workspace = workspace; this.options = options || Object.create(null); + this._onDidChangeWorkspaceName = new Emitter(); this._onDidChangeWorkspaceFolders = new Emitter(); this._onDidChangeWorkbenchState = new Emitter(); } @@ -325,7 +326,7 @@ export function workbenchInstantiationService(): IInstantiationService { } export class TestDecorationsService implements IDecorationsService { - _serviceBrand: any; + _serviceBrand: undefined; onDidChangeDecorations: Event = Event.None; registerDecorationsProvider(_provider: IDecorationsProvider): IDisposable { return Disposable.None; } getDecoration(_uri: URI, _includeChildren: boolean, _overwrite?: IDecorationData): IDecoration | undefined { return undefined; } @@ -335,7 +336,7 @@ export class TestExtensionService extends NullExtensionService { } export class TestMenuService implements IMenuService { - public _serviceBrand: any; + public _serviceBrand: undefined; createMenu(_id: MenuId, _scopedKeybindingService: IContextKeyService): IMenu { return { @@ -348,7 +349,7 @@ export class TestMenuService implements IMenuService { export class TestHistoryService implements IHistoryService { - public _serviceBrand: any; + public _serviceBrand: undefined; constructor(private root?: URI) { } @@ -392,20 +393,20 @@ export class TestHistoryService implements IHistoryService { export class TestDialogService implements IDialogService { - public _serviceBrand: any; + public _serviceBrand: undefined; public confirm(_confirmation: IConfirmation): Promise { return Promise.resolve({ confirmed: false }); } - public show(_severity: Severity, _message: string, _buttons: string[], _options?: IDialogOptions): Promise { - return Promise.resolve(0); + public show(_severity: Severity, _message: string, _buttons: string[], _options?: IDialogOptions): Promise { + return Promise.resolve({ choice: 0 }); } } export class TestFileDialogService implements IFileDialogService { - public _serviceBrand: any; + public _serviceBrand: undefined; public defaultFilePath(_schemeFilter?: string): URI | undefined { return undefined; @@ -441,7 +442,7 @@ export class TestFileDialogService implements IFileDialogService { export class TestLayoutService implements IWorkbenchLayoutService { - public _serviceBrand: any; + public _serviceBrand: undefined; dimension: IDimension = { width: 800, height: 600 }; @@ -541,6 +542,8 @@ export class TestLayoutService implements IWorkbenchLayoutService { public addClass(_clazz: string): void { } public removeClass(_clazz: string): void { } + public getMaximumEditorDimensions(): Dimension { throw new Error('not implemented'); } + public getWorkbenchContainer(): HTMLElement { throw new Error('not implemented'); } public getWorkbenchElement(): HTMLElement { throw new Error('not implemented'); } @@ -558,7 +561,7 @@ export class TestLayoutService implements IWorkbenchLayoutService { let activeViewlet: Viewlet = {} as any; export class TestViewletService implements IViewletService { - public _serviceBrand: any; + public _serviceBrand: undefined; onDidViewletRegisterEmitter = new Emitter(); onDidViewletDeregisterEmitter = new Emitter(); @@ -609,7 +612,7 @@ export class TestViewletService implements IViewletService { } export class TestPanelService implements IPanelService { - public _serviceBrand: any; + public _serviceBrand: undefined; onDidPanelOpen = new Emitter<{ panel: IPanel, focus: boolean }>().event; onDidPanelClose = new Emitter().event; @@ -658,7 +661,7 @@ export class TestStorageService extends InMemoryStorageService { } export class TestEditorGroupsService implements IEditorGroupsService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; constructor(public groups: TestEditorGroup[] = []) { } @@ -858,7 +861,7 @@ export class TestEditorGroup implements IEditorGroupView { export class TestEditorService implements EditorServiceImpl { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; onDidActiveEditorChange: Event = Event.None; onDidVisibleEditorsChange: Event = Event.None; @@ -908,7 +911,7 @@ export class TestEditorService implements EditorServiceImpl { export class TestFileService implements IFileService { - public _serviceBrand: any; + public _serviceBrand: undefined; private readonly _onFileChanges: Emitter; private readonly _onAfterOperation: Emitter; @@ -1079,7 +1082,7 @@ export class TestFileService implements IFileService { } export class TestBackupFileService implements IBackupFileService { - public _serviceBrand: any; + public _serviceBrand: undefined; public hasBackups(): Promise { return Promise.resolve(false); @@ -1144,7 +1147,7 @@ export class TestBackupFileService implements IBackupFileService { } export class TestCodeEditorService implements ICodeEditorService { - _serviceBrand: any; + _serviceBrand: undefined; onCodeEditorAdd: Event = Event.None; onCodeEditorRemove: Event = Event.None; @@ -1170,7 +1173,7 @@ export class TestCodeEditorService implements ICodeEditorService { export class TestWindowService implements IWindowService { - public _serviceBrand: any; + public _serviceBrand: undefined; onDidChangeFocus: Event = new Emitter().event; onDidChangeMaximize: Event; @@ -1301,7 +1304,7 @@ export class TestWindowService implements IWindowService { export class TestLifecycleService implements ILifecycleService { - public _serviceBrand: any; + public _serviceBrand: undefined; public phase: LifecyclePhase; public startupKind: StartupKind; @@ -1340,7 +1343,7 @@ export class TestLifecycleService implements ILifecycleService { export class TestWindowsService implements IWindowsService { - _serviceBrand: any; + _serviceBrand: undefined; public windowCount = 1; @@ -1561,7 +1564,7 @@ export class TestWindowsService implements IWindowsService { export class TestTextResourceConfigurationService implements ITextResourceConfigurationService { - _serviceBrand: any; + _serviceBrand: undefined; constructor(private configurationService = new TestConfigurationService()) { } @@ -1579,7 +1582,7 @@ export class TestTextResourceConfigurationService implements ITextResourceConfig export class TestTextResourcePropertiesService implements ITextResourcePropertiesService { - _serviceBrand: any; + _serviceBrand: undefined; constructor( @IConfigurationService private readonly configurationService: IConfigurationService, @@ -1600,7 +1603,7 @@ export class TestTextResourcePropertiesService implements ITextResourcePropertie export class TestSharedProcessService implements ISharedProcessService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: undefined; getChannel(channelName: string): any { return undefined; diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index b44e4fcbd5..2086891b4d 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -53,7 +53,7 @@ import 'vs/workbench/browser/parts/views/views'; //#region --- workbench services -import 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler'; +import 'vs/workbench/services/extensions/common/extensionUrlHandler'; import 'vs/workbench/services/bulkEdit/browser/bulkEditService'; import 'vs/workbench/services/keybinding/common/keybindingEditing'; import 'vs/workbench/services/decorations/browser/decorationsService'; @@ -76,6 +76,7 @@ import 'vs/workbench/services/label/common/labelService'; import 'vs/workbench/services/extensionManagement/common/extensionEnablementService'; import 'vs/workbench/services/notification/common/notificationService'; import 'vs/workbench/services/extensions/common/staticExtensions'; +import 'vs/workbench/services/workspace/browser/workspaceEditingService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; @@ -173,6 +174,7 @@ import 'vs/workbench/contrib/url/common/url.contribution'; // Webview import 'vs/workbench/contrib/webview/browser/webview.contribution'; +import 'vs/workbench/contrib/customEditor/browser/webviewEditor.contribution'; // Extensions Management import 'vs/workbench/contrib/extensions/browser/extensions.contribution'; @@ -220,11 +222,13 @@ import 'vs/workbench/contrib/format/browser/format.contribution'; // Themes import 'vs/workbench/contrib/themes/browser/themes.contribution'; +// Update +import 'vs/workbench/contrib/update/browser/update.contribution'; + // Watermark import 'vs/workbench/contrib/watermark/browser/watermark'; // Welcome -import 'vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution'; import 'vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay'; // Call Hierarchy diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index 9ee1e4942d..8d3373ec9e 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -30,7 +30,6 @@ import 'vs/workbench/electron-browser/desktop.main'; //#region --- workbench services import 'vs/workbench/services/integrity/node/integrityService'; import 'vs/workbench/services/textMate/electron-browser/textMateService'; -import 'vs/workbench/services/workspace/electron-browser/workspaceEditingService'; import 'vs/workbench/services/search/node/searchService'; import 'vs/workbench/services/output/node/outputChannelModelService'; import 'vs/workbench/services/textfile/node/textFileService'; @@ -245,6 +244,7 @@ import 'vs/workbench/contrib/cli/node/cli.contribution'; import 'vs/workbench/contrib/themes/test/electron-browser/themes.test.contribution'; // Welcome +import 'vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution'; import 'vs/workbench/contrib/welcome/gettingStarted/electron-browser/gettingStarted.contribution'; import 'vs/workbench/contrib/welcome/page/browser/welcomePage.contribution'; diff --git a/src/vs/workbench/workbench.web.api.ts b/src/vs/workbench/workbench.web.api.ts index 0207a117fd..af9b82b6f7 100644 --- a/src/vs/workbench/workbench.web.api.ts +++ b/src/vs/workbench/workbench.web.api.ts @@ -5,13 +5,14 @@ import 'vs/workbench/workbench.web.main'; import { main } from 'vs/workbench/browser/web.main'; -import { UriComponents } from 'vs/base/common/uri'; +import { UriComponents, URI } from 'vs/base/common/uri'; import { IFileSystemProvider } from 'vs/platform/files/common/files'; import { IWebSocketFactory } from 'vs/platform/remote/browser/browserSocketFactory'; import { ICredentialsProvider } from 'vs/workbench/services/credentials/browser/credentialsService'; import { IExtensionManifest } from 'vs/platform/extensions/common/extensions'; import { IURLCallbackProvider } from 'vs/workbench/services/url/browser/urlService'; -import { IProductConfiguration } from 'vs/platform/product/common/product'; +import { LogLevel } from 'vs/platform/log/common/log'; +import { IUpdateProvider } from 'vs/workbench/services/update/browser/updateService'; export interface IWorkbenchConstructionOptions { @@ -19,7 +20,7 @@ export interface IWorkbenchConstructionOptions { * Experimental: the remote authority is the IP:PORT from where the workbench is served * from. It is for example being used for the websocket connections as address. */ - remoteAuthority: string; + remoteAuthority?: string; /** * The connection token to send to the server. @@ -53,6 +54,11 @@ export interface IWorkbenchConstructionOptions { */ webSocketFactory?: IWebSocketFactory; + /** + * A provider for resource URIs. + */ + resourceUriProvider?: (uri: URI) => UriComponents; + /** * Experimental: Whether to enable the smoke test driver. */ @@ -74,9 +80,14 @@ export interface IWorkbenchConstructionOptions { urlCallbackProvider?: IURLCallbackProvider; /** - * Experimental: Support for product configuration. + * Current logging level. Default is `LogLevel.Info`. */ - productConfiguration?: IProductConfiguration; + logLevel?: LogLevel; + + /** + * Experimental: Support for update reporting. + */ + updateProvider?: IUpdateProvider; } /** diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 4f77cbf01f..52ab83b14f 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -38,6 +38,8 @@ import 'vs/workbench/services/telemetry/browser/telemetryService'; import 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import 'vs/workbench/services/credentials/browser/credentialsService'; import 'vs/workbench/services/url/browser/urlService'; +import 'vs/workbench/services/update/browser/updateService'; +import 'vs/workbench/contrib/stats/browser/workspaceStatsService'; import 'vs/workbench/browser/web.simpleservices'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -57,6 +59,8 @@ import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuS import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { BackupFileService } from 'vs/workbench/services/backup/common/backupFileService'; import { ExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagementService'; +import { ITunnelService } from 'vs/platform/remote/common/tunnel'; +import { NoOpTunnelService } from 'vs/platform/remote/common/tunnelService'; registerSingleton(IRequestService, RequestService, true); registerSingleton(IExtensionManagementService, ExtensionManagementService); @@ -66,15 +70,13 @@ registerSingleton(IClipboardService, BrowserClipboardService, true); registerSingleton(IAccessibilityService, BrowserAccessibilityService, true); registerSingleton(ILifecycleService, BrowserLifecycleService); registerSingleton(IContextMenuService, ContextMenuService); +registerSingleton(ITunnelService, NoOpTunnelService, true); //#endregion //#region --- workbench contributions -// Resource Service Worker -import 'vs/workbench/contrib/resources/browser/resourceServiceWorkerClient'; - // Preferences import 'vs/workbench/contrib/preferences/browser/keyboardLayoutPicker'; diff --git a/test/automation/.gitignore b/test/automation/.gitignore new file mode 100644 index 0000000000..39397c0225 --- /dev/null +++ b/test/automation/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +npm-debug.log +Thumbs.db +node_modules/ +out/ +keybindings.*.json +src/driver.d.ts diff --git a/test/automation/README.md b/test/automation/README.md new file mode 100644 index 0000000000..f33989f341 --- /dev/null +++ b/test/automation/README.md @@ -0,0 +1,3 @@ +# VS Code Automation Package + +This package contains functionality for automating various components of the VS Code UI, via an automation "driver" that connects from a separate process. It is used by the `smoke` tests. diff --git a/test/automation/package.json b/test/automation/package.json new file mode 100644 index 0000000000..a4794be8f8 --- /dev/null +++ b/test/automation/package.json @@ -0,0 +1,40 @@ +{ + "name": "vscode-automation", + "version": "1.39.0", + "description": "VS Code UI automation driver", + "author": { + "name": "Microsoft Corporation" + }, + "license": "MIT", + "main": "./out/index.js", + "private": true, + "scripts": { + "postinstall": "npm run compile", + "compile": "npm run copy-driver && npm run copy-driver-definition && tsc", + "watch": "concurrently \"npm run watch-driver\" \"npm run watch-driver-definition\" \"tsc --watch\"", + "copy-driver": "cpx src/driver.js out/", + "watch-driver": "cpx src/driver.js out/ -w", + "copy-driver-definition": "node tools/copy-driver-definition.js", + "watch-driver-definition": "watch \"node tools/copy-driver-definition.js\" ../../src/vs/platform/driver/node", + "copy-package-version": "node tools/copy-package-version.js", + "prepublishOnly": "npm run copy-package-version" + }, + "devDependencies": { + "@types/mkdirp": "0.5.1", + "@types/ncp": "2.0.1", + "@types/node": "8.0.33", + "@types/puppeteer": "^1.19.0", + "@types/tmp": "0.1.0", + "concurrently": "^3.5.1", + "cpx": "^1.5.0", + "typescript": "2.9.2", + "watch": "^1.0.2" + }, + "dependencies": { + "mkdirp": "^0.5.1", + "ncp": "^2.0.0", + "puppeteer": "^1.19.0", + "tmp": "0.1.0", + "vscode-uri": "^2.0.3" + } +} diff --git a/test/smoke/src/areas/activitybar/activityBar.ts b/test/automation/src/activityBar.ts similarity index 95% rename from test/smoke/src/areas/activitybar/activityBar.ts rename to test/automation/src/activityBar.ts index 2c3715a6a6..3914df606d 100644 --- a/test/smoke/src/areas/activitybar/activityBar.ts +++ b/test/automation/src/activityBar.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Code } from '../../vscode/code'; +import { Code } from './code'; export const enum ActivityBarPosition { LEFT = 0, @@ -27,4 +27,4 @@ export class ActivityBar { await this.code.waitForElement(`.part.activitybar.${positionClass}`); } -} \ No newline at end of file +} diff --git a/test/smoke/src/application.ts b/test/automation/src/application.ts similarity index 90% rename from test/smoke/src/application.ts rename to test/automation/src/application.ts index 4c107794c5..07f3dbe9ca 100644 --- a/test/smoke/src/application.ts +++ b/test/automation/src/application.ts @@ -5,8 +5,8 @@ import * as fs from 'fs'; import * as path from 'path'; -import { Workbench } from './areas/workbench/workbench'; -import { Code, spawn, SpawnOptions } from './vscode/code'; +import { Workbench } from './workbench'; +import { Code, spawn, SpawnOptions } from './code'; import { Logger } from './logger'; export const enum Quality { @@ -25,7 +25,7 @@ export interface ApplicationOptions extends SpawnOptions { export class Application { private _code: Code | undefined; - private _workbench: Workbench; + private _workbench: Workbench | undefined; constructor(private options: ApplicationOptions) { this._workspacePathOrFolder = options.workspacePath; @@ -40,7 +40,7 @@ export class Application { } get workbench(): Workbench { - return this._workbench; + return this._workbench!; } get logger(): Logger { @@ -74,7 +74,7 @@ export class Application { await this.code.waitForElement('.explorer-folders-view'); if (expectWalkthroughPart) { - await this.code.waitForActiveElement(`.editor-instance[id="workbench.editor.walkThroughPart"] > div > div[tabIndex="0"]`); + await this.code.waitForActiveElement(`.editor-instance[data-editor-id="workbench.editor.walkThroughPart"] > div > div[tabIndex="0"]`); } */ //{{SQL CARBON EDIT}} @@ -149,7 +149,7 @@ export class Application { await this.code.waitForElement('.monaco-workbench'); if (this.remote) { - await this.code.waitForElement('.monaco-workbench .statusbar-item[id="status.host"]'); + await this.code.waitForTextContent('.monaco-workbench .statusbar-item[id="status.host"]', ' TestResolver'); } // wait a bit, since focus might be stolen off widgets diff --git a/test/smoke/src/vscode/code.ts b/test/automation/src/code.ts similarity index 97% rename from test/smoke/src/vscode/code.ts rename to test/automation/src/code.ts index 00c3a2fefd..7dec7a5d26 100644 --- a/test/smoke/src/vscode/code.ts +++ b/test/automation/src/code.ts @@ -11,11 +11,11 @@ import * as mkdirp from 'mkdirp'; import { tmpName } from 'tmp'; import { IDriver, connect as connectElectronDriver, IDisposable, IElement, Thenable } from './driver'; import { connect as connectPuppeteerDriver, launch } from './puppeteerDriver'; -import { Logger } from '../logger'; +import { Logger } from './logger'; import { ncp } from 'ncp'; import { URI } from 'vscode-uri'; -const repoPath = path.join(__dirname, '../../../..'); +const repoPath = path.join(__dirname, '../../..'); function getDevElectronPath(): string { const buildPath = path.join(repoPath, '.build'); @@ -237,13 +237,14 @@ export class Code { throw new Error('Invalid usage'); } - if (typeof target[prop] !== 'function') { - return target[prop]; + const targetProp = (target as any)[prop]; + if (typeof targetProp !== 'function') { + return targetProp; } - return function (...args) { + return function (this: any, ...args: any[]) { logger.log(`${prop}`, ...args.filter(a => typeof a === 'string')); - return target[prop].apply(this, args); + return targetProp.apply(this, args); }; } }); diff --git a/test/smoke/src/areas/debug/debugSmoke.ts b/test/automation/src/debug.ts similarity index 90% rename from test/smoke/src/areas/debug/debugSmoke.ts rename to test/automation/src/debug.ts index dba2a65ac7..c0ec2c172d 100644 --- a/test/smoke/src/areas/debug/debugSmoke.ts +++ b/test/automation/src/debug.ts @@ -3,12 +3,12 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Viewlet } from '../workbench/viewlet'; -import { Commands } from '../workbench/workbench'; -import { Code, findElement } from '../../vscode/code'; -import { Editors } from '../editor/editors'; -import { Editor } from '../editor/editor'; -import { IElement } from '../../vscode/driver'; +import { Viewlet } from './viewlet'; +import { Commands } from './workbench'; +import { Code, findElement } from './code'; +import { Editors } from './editors'; +import { Editor } from './editor'; +import { IElement } from '../src/driver'; const VIEWLET = 'div[id="workbench.view.debug"]'; const DEBUG_VIEW = `${VIEWLET} .debug-view-content`; @@ -25,10 +25,10 @@ const DEBUG_STATUS_BAR = `.statusbar.debugging`; const NOT_DEBUG_STATUS_BAR = `.statusbar:not(debugging)`; const TOOLBAR_HIDDEN = `.debug-toolbar[aria-hidden="true"]`; const STACK_FRAME = `${VIEWLET} .monaco-list-row .stack-frame`; -const SPECIFIC_STACK_FRAME = filename => `${STACK_FRAME} .file[title*="${filename}"]`; +const SPECIFIC_STACK_FRAME = (filename: string) => `${STACK_FRAME} .file[title*="${filename}"]`; const VARIABLE = `${VIEWLET} .debug-variables .monaco-list-row .expression`; const CONSOLE_OUTPUT = `.repl .output.expression .value`; -const CONSOLE_INPUT_OUTPUT = `.repl .input-output-pair .output.expression .value`; +const CONSOLE_EVALUATION_RESULT = `.repl .evaluation-result.expression .value`; const REPL_FOCUSED = '.repl-input-wrapper .monaco-editor textarea'; @@ -132,8 +132,8 @@ export class Debug extends Viewlet { // Wait for the keys to be picked up by the editor model such that repl evalutes what just got typed await this.editor.waitForEditorContents('debug:replinput', s => s.indexOf(text) >= 0); await this.code.dispatchKeybinding('enter'); - await this.code.waitForElement(CONSOLE_INPUT_OUTPUT); - await this.waitForOutput(output => accept(output[output.length - 1] || '')); + await this.code.waitForElements(CONSOLE_EVALUATION_RESULT, false, + elements => !!elements.length && accept(elements[elements.length - 1].textContent)); } // Different node versions give different number of variables. As a workaround be more relaxed when checking for variable count diff --git a/test/smoke/src/vscode/driver.js b/test/automation/src/driver.js similarity index 100% rename from test/smoke/src/vscode/driver.js rename to test/automation/src/driver.js diff --git a/test/smoke/src/areas/editor/editor.ts b/test/automation/src/editor.ts similarity index 94% rename from test/smoke/src/areas/editor/editor.ts rename to test/automation/src/editor.ts index 1d03827edd..09058cb5a7 100644 --- a/test/smoke/src/areas/editor/editor.ts +++ b/test/automation/src/editor.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { References } from './peek'; -import { Commands } from '../workbench/workbench'; -import { Code } from '../../vscode/code'; +import { Commands } from './workbench'; +import { Code } from './code'; const RENAME_BOX = '.monaco-editor .monaco-editor.rename-box'; const RENAME_INPUT = `${RENAME_BOX} .rename-input`; -const EDITOR = filename => `.monaco-editor[data-uri$="${filename}"]`; -const VIEW_LINES = filename => `${EDITOR(filename)} .view-lines`; -const LINE_NUMBERS = filename => `${EDITOR(filename)} .margin .margin-view-overlays .line-numbers`; +const EDITOR = (filename: string) => `.monaco-editor[data-uri$="${filename}"]`; +const VIEW_LINES = (filename: string) => `${EDITOR(filename)} .view-lines`; +const LINE_NUMBERS = (filename: string) => `${EDITOR(filename)} .margin .margin-view-overlays .line-numbers`; export class Editor { @@ -130,4 +130,4 @@ export class Editor { throw new Error('Line not found'); } -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/editor/editors.ts b/test/automation/src/editors.ts similarity index 97% rename from test/smoke/src/areas/editor/editors.ts rename to test/automation/src/editors.ts index 7d9f71e7be..c5f7f2f967 100644 --- a/test/smoke/src/areas/editor/editors.ts +++ b/test/automation/src/editors.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Code } from '../../vscode/code'; +import { Code } from './code'; export class Editors { @@ -49,4 +49,4 @@ export class Editors { await this.waitForEditorFocus('Untitled-1', true); } -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/explorer/explorer.ts b/test/automation/src/explorer.ts similarity index 92% rename from test/smoke/src/areas/explorer/explorer.ts rename to test/automation/src/explorer.ts index 5c3f2a99e5..77fc479f6a 100644 --- a/test/smoke/src/areas/explorer/explorer.ts +++ b/test/automation/src/explorer.ts @@ -3,9 +3,9 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Viewlet } from '../workbench/viewlet'; -import { Editors } from '../editor/editors'; -import { Code } from '../../vscode/code'; +import { Viewlet } from './viewlet'; +import { Editors } from './editors'; +import { Code } from './code'; export class Explorer extends Viewlet { @@ -45,4 +45,4 @@ export class Explorer extends Viewlet { throw new Error('No class defined for this file extension'); } -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/extensions/extensions.ts b/test/automation/src/extensions.ts similarity index 94% rename from test/smoke/src/areas/extensions/extensions.ts rename to test/automation/src/extensions.ts index d23e49f4d4..691947ce28 100644 --- a/test/smoke/src/areas/extensions/extensions.ts +++ b/test/automation/src/extensions.ts @@ -3,8 +3,8 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Viewlet } from '../workbench/viewlet'; -import { Code } from '../../vscode/code'; +import { Viewlet } from './viewlet'; +import { Code } from './code'; const SEARCH_BOX = 'div.extensions-viewlet[id="workbench.view.extensions"] .monaco-editor textarea'; @@ -40,4 +40,4 @@ export class Extensions extends Viewlet { await this.code.waitAndClick(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-list-row[aria-label="${ariaLabel}"] .extension li[class='action-item'] .extension-action.install`); await this.code.waitForElement(`.extension-editor .monaco-action-bar .action-item:not(.disabled) .extension-action.uninstall`); } -} \ No newline at end of file +} diff --git a/test/automation/src/index.ts b/test/automation/src/index.ts new file mode 100644 index 0000000000..118a757690 --- /dev/null +++ b/test/automation/src/index.ts @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export * from './activityBar'; +export * from './application'; +export * from './code'; +export * from './debug'; +export * from './editor'; +export * from './editors'; +export * from './explorer'; +export * from './extensions'; +export * from './keybindings'; +export * from './logger'; +export * from './peek'; +export * from './problems'; +export * from './quickinput'; +export * from './quickopen'; +export * from './scm'; +export * from './search'; +export * from './settings'; +export * from './statusbar'; +export * from './terminal'; +export * from './viewlet'; +export * from './workbench'; +export * from '../src/driver'; + +// {{SQL CARBON EDIT}} +export * from './sql/connectionDialog'; +export * from './sql/profiler'; +export * from './sql/queryEditors'; +export * from './sql/sqlutils'; +export * from './sql/testConfig'; diff --git a/test/smoke/src/areas/preferences/keybindings.ts b/test/automation/src/keybindings.ts similarity index 97% rename from test/smoke/src/areas/preferences/keybindings.ts rename to test/automation/src/keybindings.ts index 3016badb1e..b5f9ff684a 100644 --- a/test/smoke/src/areas/preferences/keybindings.ts +++ b/test/automation/src/keybindings.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Code } from '../../vscode/code'; +import { Code } from './code'; const SEARCH_INPUT = '.keybindings-header .settings-search-input input'; @@ -31,4 +31,4 @@ export class KeybindingsEditor { await this.code.dispatchKeybinding('enter'); await this.code.waitForElement(`.keybindings-list-container div[aria-label="Keybinding is ${ariaLabel}."]`); } -} \ No newline at end of file +} diff --git a/test/smoke/src/logger.ts b/test/automation/src/logger.ts similarity index 100% rename from test/smoke/src/logger.ts rename to test/automation/src/logger.ts diff --git a/test/smoke/src/areas/editor/peek.ts b/test/automation/src/peek.ts similarity index 97% rename from test/smoke/src/areas/editor/peek.ts rename to test/automation/src/peek.ts index 1cb127456e..87795c472e 100644 --- a/test/smoke/src/areas/editor/peek.ts +++ b/test/automation/src/peek.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Code } from '../../vscode/code'; +import { Code } from './code'; export class References { diff --git a/test/smoke/src/areas/problems/problems.ts b/test/automation/src/problems.ts similarity index 97% rename from test/smoke/src/areas/problems/problems.ts rename to test/automation/src/problems.ts index 77d6dcabf4..4701750088 100644 --- a/test/smoke/src/areas/problems/problems.ts +++ b/test/automation/src/problems.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Code } from '../../vscode/code'; +import { Code } from './code'; export const enum ProblemSeverity { WARNING = 0, diff --git a/test/smoke/src/vscode/puppeteerDriver.ts b/test/automation/src/puppeteerDriver.ts similarity index 67% rename from test/smoke/src/vscode/puppeteerDriver.ts rename to test/automation/src/puppeteerDriver.ts index 5bd8fb3fe3..fd3291fe74 100644 --- a/test/smoke/src/vscode/puppeteerDriver.ts +++ b/test/automation/src/puppeteerDriver.ts @@ -8,11 +8,12 @@ import { ChildProcess, spawn } from 'child_process'; import { join } from 'path'; import { mkdir } from 'fs'; import { promisify } from 'util'; +import { IDriver, IDisposable } from './driver'; const width = 1200; const height = 800; -const vscodeToPuppeteerKey = { +const vscodeToPuppeteerKey: { [key: string]: string } = { cmd: 'Meta', ctrl: 'Control', shift: 'Shift', @@ -111,7 +112,7 @@ function teardown(): void { function waitForEndpoint(): Promise { return new Promise(r => { - server!.stdout.on('data', d => { + server!.stdout.on('data', (d: Buffer) => { const matches = d.toString('ascii').match(/Web UI available at (.+)/); if (matches !== null) { r(matches[1]); @@ -139,54 +140,3 @@ export function connect(headless: boolean, outPath: string, handle: string): Pro c(result); }); } - -/** - * Thenable is a common denominator between ES6 promises, Q, jquery.Deferred, WinJS.Promise, - * and others. This API makes no assumption about what promise library is being used which - * enables reusing existing code without migrating to a specific promise implementation. Still, - * we recommend the use of native promises which are available in this editor. - */ -export interface Thenable { - /** - * Attaches callbacks for the resolution and/or rejection of the Promise. - * @param onfulfilled The callback to execute when the Promise is resolved. - * @param onrejected The callback to execute when the Promise is rejected. - * @returns A Promise for the completion of which ever callback is executed. - */ - then(onfulfilled?: (value: T) => TResult | Thenable, onrejected?: (reason: any) => TResult | Thenable): Thenable; - then(onfulfilled?: (value: T) => TResult | Thenable, onrejected?: (reason: any) => void): Thenable; -} - -export interface IElement { - tagName: string; - className: string; - textContent: string; - attributes: { [name: string]: string; }; - children: IElement[]; - top: number; - left: number; -} - -export interface IDriver { - _serviceBrand: any; - - getWindowIds(): Promise; - capturePage(windowId: number): Promise; - reloadWindow(windowId: number): Promise; - exitApplication(): Promise; - dispatchKeybinding(windowId: number, keybinding: string): Promise; - click(windowId: number, selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Promise; - doubleClick(windowId: number, selector: string): Promise; - setValue(windowId: number, selector: string, text: string): Promise; - getTitle(windowId: number): Promise; - isActiveElement(windowId: number, selector: string): Promise; - getElements(windowId: number, selector: string, recursive?: boolean): Promise; - getElementXY(windowId: number, selector: string, xoffset?: number, yoffset?: number): Promise<{ x: number; y: number; }>; - typeInEditor(windowId: number, selector: string, text: string): Promise; - getTerminalBuffer(windowId: number, selector: string): Promise; - writeInTerminal(windowId: number, selector: string, text: string): Promise; -} - -export interface IDisposable { - dispose(): void; -} diff --git a/test/smoke/src/areas/quickinput/quickinput.ts b/test/automation/src/quickinput.ts similarity index 97% rename from test/smoke/src/areas/quickinput/quickinput.ts rename to test/automation/src/quickinput.ts index 130b30bbdb..7f428516fb 100644 --- a/test/smoke/src/areas/quickinput/quickinput.ts +++ b/test/automation/src/quickinput.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Code } from '../../vscode/code'; +import { Code } from './code'; export class QuickInput { diff --git a/test/smoke/src/areas/quickopen/quickopen.ts b/test/automation/src/quickopen.ts similarity index 97% rename from test/smoke/src/areas/quickopen/quickopen.ts rename to test/automation/src/quickopen.ts index 09937240b8..fa8687b009 100644 --- a/test/smoke/src/areas/quickopen/quickopen.ts +++ b/test/automation/src/quickopen.ts @@ -3,8 +3,8 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Editors } from '../editor/editors'; -import { Code } from '../../vscode/code'; +import { Editors } from './editors'; +import { Code } from './code'; export class QuickOpen { diff --git a/test/smoke/src/areas/git/scm.ts b/test/automation/src/scm.ts similarity index 94% rename from test/smoke/src/areas/git/scm.ts rename to test/automation/src/scm.ts index 437f80a3aa..7fed8d48b0 100644 --- a/test/smoke/src/areas/git/scm.ts +++ b/test/automation/src/scm.ts @@ -3,9 +3,9 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Viewlet } from '../workbench/viewlet'; -import { IElement } from '../../vscode/driver'; -import { findElement, findElements, Code } from '../../vscode/code'; +import { Viewlet } from './viewlet'; +import { IElement } from '../src/driver'; +import { findElement, findElements, Code } from './code'; const VIEWLET = 'div[id="workbench.view.scm"]'; const SCM_INPUT = `${VIEWLET} .scm-editor textarea`; @@ -76,4 +76,4 @@ export class SCM extends Viewlet { await this.code.waitForSetValue(SCM_INPUT, message); await this.code.waitAndClick(COMMIT_COMMAND); } -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/search/search.ts b/test/automation/src/search.ts similarity index 95% rename from test/smoke/src/areas/search/search.ts rename to test/automation/src/search.ts index ffc2511518..80dd41822a 100644 --- a/test/smoke/src/areas/search/search.ts +++ b/test/automation/src/search.ts @@ -3,13 +3,13 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Viewlet } from '../workbench/viewlet'; -import { Code } from '../../vscode/code'; +import { Viewlet } from './viewlet'; +import { Code } from './code'; const VIEWLET = '.search-view'; const INPUT = `${VIEWLET} .search-widget .search-container .monaco-inputbox textarea`; const INCLUDE_INPUT = `${VIEWLET} .query-details .file-types.includes .monaco-inputbox input`; -const FILE_MATCH = filename => `${VIEWLET} .results .filematch[data-resource$="${filename}"]`; +const FILE_MATCH = (filename: string) => `${VIEWLET} .results .filematch[data-resource$="${filename}"]`; async function retry(setup: () => Promise, attempt: () => Promise) { let count = 0; diff --git a/test/smoke/src/areas/preferences/settings.ts b/test/automation/src/settings.ts similarity index 84% rename from test/smoke/src/areas/preferences/settings.ts rename to test/automation/src/settings.ts index b08082d494..e92dfe8a25 100644 --- a/test/smoke/src/areas/preferences/settings.ts +++ b/test/automation/src/settings.ts @@ -5,15 +5,10 @@ import * as fs from 'fs'; import * as path from 'path'; -import { Editor } from '../editor/editor'; -import { Editors } from '../editor/editors'; -import { Code } from '../../vscode/code'; -import { QuickOpen } from '../quickopen/quickopen'; - -export const enum ActivityBarPosition { - LEFT = 0, - RIGHT = 1 -} +import { Editor } from './editor'; +import { Editors } from './editors'; +import { Code } from './code'; +import { QuickOpen } from './quickopen'; export class SettingsEditor { diff --git a/test/smoke/src/sql/connectionDialog/connectionDialog.ts b/test/automation/src/sql/connectionDialog.ts similarity index 92% rename from test/smoke/src/sql/connectionDialog/connectionDialog.ts rename to test/automation/src/sql/connectionDialog.ts index cec5a6178c..521b70a42d 100644 --- a/test/smoke/src/sql/connectionDialog/connectionDialog.ts +++ b/test/automation/src/sql/connectionDialog.ts @@ -3,9 +3,9 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Code } from '../../vscode/code'; -import { waitForNewDialog, clickDialogButton } from '../sqlutils'; -import { TestServerProfile, AuthenticationType } from '../testConfig'; +import { Code } from '../code'; +import { waitForNewDialog, clickDialogButton } from './sqlutils'; +import { TestServerProfile, AuthenticationType } from './testConfig'; const CONNECTION_DIALOG_TITLE = 'Connection'; const CONNECTION_DIALOG_SELECTOR: string = '.modal-dialog .modal-content .modal-body .connection-dialog'; @@ -48,4 +48,4 @@ export class ConnectionDialog { private async selectAuthType(authType: string) { await this.code.waitAndClick(`.context-view.bottom.left .monaco-select-box-dropdown-container .select-box-dropdown-list-container .monaco-list .monaco-scrollable-element .monaco-list-rows .monaco-list-row div[aria-label="${authType}"][class*="option-text"]`); } -} \ No newline at end of file +} diff --git a/test/smoke/src/sql/profiler/profiler.ts b/test/automation/src/sql/profiler.ts similarity index 83% rename from test/smoke/src/sql/profiler/profiler.ts rename to test/automation/src/sql/profiler.ts index 38de95ca70..7e4dd241a7 100644 --- a/test/smoke/src/sql/profiler/profiler.ts +++ b/test/automation/src/sql/profiler.ts @@ -3,9 +3,9 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Code } from '../../vscode/code'; -import { QuickOpen } from '../../areas/quickopen/quickopen'; -import { waitForNewDialog, clickDialogButton } from '../sqlutils'; +import { Code } from '../code'; +import { QuickOpen } from '../quickopen'; +import { waitForNewDialog, clickDialogButton } from './sqlutils'; const NEW_SESSION_DIALOG_TITLE: string = 'Start New Profiler Session'; @@ -25,4 +25,4 @@ export class Profiler { await this.waitForNewSessionDialog(); await clickDialogButton(this.code, 'Start'); } -} \ No newline at end of file +} diff --git a/test/smoke/src/sql/queryEditor/queryEditors.ts b/test/automation/src/sql/queryEditors.ts similarity index 93% rename from test/smoke/src/sql/queryEditor/queryEditors.ts rename to test/automation/src/sql/queryEditors.ts index 72b0fb5f68..d0b09ae88e 100644 --- a/test/smoke/src/sql/queryEditor/queryEditors.ts +++ b/test/automation/src/sql/queryEditors.ts @@ -3,9 +3,9 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Editors } from '../../areas/editor/editors'; -import { QuickOpen } from '../../areas/quickopen/quickopen'; -import { Code } from '../../vscode/code'; +import { Editors } from '../editors'; +import { QuickOpen } from '../quickopen'; +import { Code } from '../code'; import * as path from 'path'; export class QueryEditors extends Editors { diff --git a/test/smoke/src/sql/sqlutils.ts b/test/automation/src/sql/sqlutils.ts similarity index 94% rename from test/smoke/src/sql/sqlutils.ts rename to test/automation/src/sql/sqlutils.ts index cb604b51f4..8a64137d9e 100644 --- a/test/smoke/src/sql/sqlutils.ts +++ b/test/automation/src/sql/sqlutils.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Code } from '../vscode/code'; +import { Code } from '../code'; export async function waitForNewDialog(code: Code, title: string) { await code.waitForElement(`div[aria-label="${title}"][class="modal fade flyout-dialog"]`); @@ -11,4 +11,4 @@ export async function waitForNewDialog(code: Code, title: string) { export async function clickDialogButton(code: Code, title: string) { await code.waitAndClick(`.modal-dialog .modal-content .modal-footer .right-footer .footer-button a[aria-label="${title}"][aria-disabled="false"]`); -} \ No newline at end of file +} diff --git a/test/smoke/src/sql/testConfig.ts b/test/automation/src/sql/testConfig.ts similarity index 97% rename from test/smoke/src/sql/testConfig.ts rename to test/automation/src/sql/testConfig.ts index cbb1fdb6a6..9e2d5a8334 100644 --- a/test/smoke/src/sql/testConfig.ts +++ b/test/automation/src/sql/testConfig.ts @@ -41,8 +41,8 @@ export enum EngineType { BigDataCluster } -let connectionProviderMapping = {}; -let authenticationTypeMapping = {}; +let connectionProviderMapping: { [key: string]: any } = {}; +let authenticationTypeMapping: { [key: string]: any } = {}; connectionProviderMapping[ConnectionProvider.SQLServer] = { name: 'MSSQL', displayName: 'Microsoft SQL Server' }; authenticationTypeMapping[AuthenticationType.SqlLogin] = { name: 'SqlLogin', displayName: 'SQL Login' }; diff --git a/test/smoke/src/areas/statusbar/statusbar.ts b/test/automation/src/statusbar.ts similarity index 98% rename from test/smoke/src/areas/statusbar/statusbar.ts rename to test/automation/src/statusbar.ts index c477b0a1cb..c2c7dfaac0 100644 --- a/test/smoke/src/areas/statusbar/statusbar.ts +++ b/test/automation/src/statusbar.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Code } from '../../vscode/code'; +import { Code } from './code'; export const enum StatusBarElement { BRANCH_STATUS = 0, diff --git a/test/smoke/src/areas/terminal/terminal.ts b/test/automation/src/terminal.ts similarity index 93% rename from test/smoke/src/areas/terminal/terminal.ts rename to test/automation/src/terminal.ts index 556797c8b3..4016d9e455 100644 --- a/test/smoke/src/areas/terminal/terminal.ts +++ b/test/automation/src/terminal.ts @@ -3,8 +3,8 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Code } from '../../vscode/code'; -import { QuickOpen } from '../quickopen/quickopen'; +import { Code } from './code'; +import { QuickOpen } from './quickopen'; const PANEL_SELECTOR = 'div[id="workbench.panel.terminal"]'; const XTERM_SELECTOR = `${PANEL_SELECTOR} .terminal-wrapper`; @@ -30,4 +30,4 @@ export class Terminal { async waitForTerminalText(accept: (buffer: string[]) => boolean): Promise { await this.code.waitForTerminalBuffer(XTERM_SELECTOR, accept); } -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/workbench/viewlet.ts b/test/automation/src/viewlet.ts similarity index 93% rename from test/smoke/src/areas/workbench/viewlet.ts rename to test/automation/src/viewlet.ts index 315b44c4c4..d18a1e4815 100644 --- a/test/smoke/src/areas/workbench/viewlet.ts +++ b/test/automation/src/viewlet.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Code } from '../../vscode/code'; +import { Code } from './code'; export abstract class Viewlet { @@ -12,4 +12,4 @@ export abstract class Viewlet { async waitForTitle(fn: (title: string) => boolean): Promise { await this.code.waitForTextContent('.monaco-workbench .part.sidebar > .title > .title-label > h2', undefined, fn); } -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/workbench/workbench.ts b/test/automation/src/workbench.ts similarity index 68% rename from test/smoke/src/areas/workbench/workbench.ts rename to test/automation/src/workbench.ts index 1c35f4cb2e..447351b4a1 100644 --- a/test/smoke/src/areas/workbench/workbench.ts +++ b/test/automation/src/workbench.ts @@ -3,27 +3,27 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Explorer } from '../explorer/explorer'; -import { ActivityBar } from '../activitybar/activityBar'; -import { QuickOpen } from '../quickopen/quickopen'; -import { QuickInput } from '../quickinput/quickinput'; -import { Extensions } from '../extensions/extensions'; -import { Search } from '../search/search'; -import { Editor } from '../editor/editor'; -import { SCM } from '../git/scm'; -import { Debug } from '../debug/debugSmoke'; -import { StatusBar } from '../statusbar/statusbar'; -import { Problems } from '../problems/problems'; -import { SettingsEditor } from '../preferences/settings'; -import { KeybindingsEditor } from '../preferences/keybindings'; -import { Editors } from '../editor/editors'; -import { Code } from '../../vscode/code'; -import { Terminal } from '../terminal/terminal'; +import { Explorer } from './explorer'; +import { ActivityBar } from './activityBar'; +import { QuickOpen } from './quickopen'; +import { QuickInput } from './quickinput'; +import { Extensions } from './extensions'; +import { Search } from './search'; +import { Editor } from './editor'; +import { SCM } from './scm'; +import { Debug } from './debug'; +import { StatusBar } from './statusbar'; +import { Problems } from './problems'; +import { SettingsEditor } from './settings'; +import { KeybindingsEditor } from './keybindings'; +import { Editors } from './editors'; +import { Code } from './code'; +import { Terminal } from './terminal'; // {{SQL CARBON EDIT}} -import { ConnectionDialog } from '../../sql/connectionDialog/connectionDialog'; -import { Profiler } from '../../sql/profiler/profiler'; -import { QueryEditors } from '../../sql/queryEditor/queryEditors'; +import { ConnectionDialog } from './sql/connectionDialog'; +import { Profiler } from './sql/profiler'; +import { QueryEditors } from './sql/queryEditors'; // {{END}} export interface Commands { diff --git a/test/smoke/tools/copy-driver-definition.js b/test/automation/tools/copy-driver-definition.js similarity index 90% rename from test/smoke/tools/copy-driver-definition.js rename to test/automation/tools/copy-driver-definition.js index 4a53732f4e..28907fd03d 100644 --- a/test/smoke/tools/copy-driver-definition.js +++ b/test/automation/tools/copy-driver-definition.js @@ -44,7 +44,8 @@ export interface IDisposable { export function connect(outPath: string, handle: string): Promise<{ client: IDisposable, driver: IDriver }>; `; -const srcPath = path.join(path.dirname(__dirname), 'src/vscode'); -const outDriverPath = path.join(srcPath, 'driver.d.ts'); +const srcPath = path.join(path.dirname(__dirname), 'src'); +const outPath = path.join(path.dirname(__dirname), 'out'); -fs.writeFileSync(outDriverPath, contents); +fs.writeFileSync(path.join(srcPath, 'driver.d.ts'), contents); +fs.writeFileSync(path.join(outPath, 'driver.d.ts'), contents); diff --git a/test/automation/tools/copy-package-version.js b/test/automation/tools/copy-package-version.js new file mode 100644 index 0000000000..bb0b871a7f --- /dev/null +++ b/test/automation/tools/copy-package-version.js @@ -0,0 +1,19 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const fs = require('fs'); +const path = require('path'); + +const packageDir = path.dirname(__dirname); +const root = path.dirname(path.dirname(path.dirname(__dirname))); + +const rootPackageJsonFile = path.join(root, 'package.json'); +const thisPackageJsonFile = path.join(packageDir, 'package.json'); +const rootPackageJson = JSON.parse(fs.readFileSync(rootPackageJsonFile, 'utf8')); +const thisPackageJson = JSON.parse(fs.readFileSync(thisPackageJsonFile, 'utf8')); + +thisPackageJson.version = rootPackageJson.version; + +fs.writeFileSync(thisPackageJsonFile, JSON.stringify(thisPackageJson, null, ' ')); diff --git a/test/automation/tsconfig.json b/test/automation/tsconfig.json new file mode 100644 index 0000000000..eecaf21a69 --- /dev/null +++ b/test/automation/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2016", + "strict": true, + "noUnusedParameters": false, + "noUnusedLocals": true, + "outDir": "out", + "sourceMap": true, + "declaration": true, + "lib": [ + "es2016", + "dom" + ] + }, + "exclude": [ + "node_modules", + "out", + "tools", + ] +} diff --git a/test/automation/yarn.lock b/test/automation/yarn.lock new file mode 100644 index 0000000000..60949e0192 --- /dev/null +++ b/test/automation/yarn.lock @@ -0,0 +1,1842 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/mkdirp@0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.5.1.tgz#ea887cd024f691c1ca67cce20b7606b053e43b0f" + integrity sha512-XA4vNO6GCBz8Smq0hqSRo4yRWMqr4FPQrWjhJt6nKskzly4/p87SfuJMFYGRyYb6jo2WNIQU2FDBsY5r1BibUA== + dependencies: + "@types/node" "*" + +"@types/ncp@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/ncp/-/ncp-2.0.1.tgz#749432511f6ad747d04e98837b18cca9045567fb" + integrity sha512-TeiJ7uvv/92ugSqZ0v9l0eNXzutlki0aK+R1K5bfA5SYUil46ITlxLW4iNTCf55P4L5weCmaOdtxGeGWvudwPg== + dependencies: + "@types/node" "*" + +"@types/node@*": + version "12.7.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.1.tgz#3b5c3a26393c19b400844ac422bd0f631a94d69d" + integrity sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw== + +"@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/puppeteer@^1.19.0": + version "1.19.1" + resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-1.19.1.tgz#942ca62288953a0f5fbbc25c103b5f2ba28b60ab" + integrity sha512-ReWZvoEfMiJIA3AG+eM+nCx5GKrU2ANVYY5TC0nbpeiTCtnJbcqnmBbR8TkXMBTvLBYcuTOAELbTcuX73siDNQ== + dependencies: + "@types/node" "*" + +"@types/tmp@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.1.0.tgz#19cf73a7bcf641965485119726397a096f0049bd" + integrity sha512-6IwZ9HzWbCq6XoQWhxLpDjuADodH/MKXRUIDFudvgjcVdjFknvmR+DNsoUeer4XPrEnrZs04Jj+kfV9pFsrhmA== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + integrity sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA== + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= + dependencies: + arr-flatten "^1.0.1" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +babel-runtime@^6.9.2: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +chalk@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chokidar@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg= + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +chownr@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6" + integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +commander@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.6.0.tgz#9df7e52fb2a0cb0fb89058ee80c3104225f37e1d" + integrity sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +concurrently@^3.5.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-3.6.1.tgz#2f95baec5c4051294dfbb55b57a3b98a3e2b45ec" + integrity sha512-/+ugz+gwFSEfTGUxn0KHkY+19XPRTXR8+7oUK/HxgiN1n7FjeJmkrbSiXAJfyQ0zORgJYPaenmymwon51YXH9Q== + dependencies: + chalk "^2.4.1" + commander "2.6.0" + date-fns "^1.23.0" + lodash "^4.5.1" + read-pkg "^3.0.0" + rx "2.3.24" + spawn-command "^0.0.2-1" + supports-color "^3.2.3" + tree-kill "^1.1.0" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-js@^2.4.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" + integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cpx@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/cpx/-/cpx-1.5.0.tgz#185be018511d87270dedccc293171e37655ab88f" + integrity sha1-GFvgGFEdhycN7czCkxceN2VauI8= + dependencies: + babel-runtime "^6.9.2" + chokidar "^1.6.0" + duplexer "^0.1.1" + glob "^7.0.5" + glob2base "^0.0.12" + minimatch "^3.0.2" + mkdirp "^0.5.1" + resolve "^1.1.7" + safe-buffer "^5.0.1" + shell-quote "^1.6.1" + subarg "^1.0.0" + +date-fns@^1.23.0: + version "1.30.1" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" + integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.1.0, debug@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + +duplexer@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +exec-sh@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" + integrity sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== + dependencies: + merge "^1.2.0" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= + dependencies: + is-posix-bracket "^0.1.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= + dependencies: + fill-range "^2.1.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= + dependencies: + is-extglob "^1.0.0" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extract-zip@^1.6.6: + version "1.6.7" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" + integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k= + dependencies: + concat-stream "1.6.2" + debug "2.6.9" + mkdirp "0.5.1" + yauzl "2.4.1" + +fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + integrity sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU= + dependencies: + pend "~1.2.0" + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= + +fill-range@^2.1.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^3.0.0" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +find-index@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" + integrity sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ= + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= + dependencies: + for-in "^1.0.1" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fs-minipass@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" + integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ== + dependencies: + minipass "^2.2.1" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.0.0: + version "1.2.9" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" + integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== + dependencies: + nan "^2.12.1" + node-pre-gyp "^0.12.0" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= + dependencies: + is-glob "^2.0.0" + +glob2base@^0.0.12: + version "0.0.12" + resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56" + integrity sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY= + dependencies: + find-index "^0.1.1" + +glob@^7.0.5, glob@^7.1.3: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02" + integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q== + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +hosted-git-info@^2.1.4: + version "2.8.4" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.4.tgz#44119abaf4bc64692a16ace34700fed9c03e2546" + integrity sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ== + +https-proxy-agent@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz#271ea8e90f836ac9f119daccd39c19ff7dfb0793" + integrity sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg== + dependencies: + agent-base "^4.3.0" + debug "^3.1.0" + +iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== + dependencies: + minimatch "^3.0.4" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= + dependencies: + is-extglob "^1.0.0" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + +lodash@^4.5.1: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +math-random@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" + integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== + +merge@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" + integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== + +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +micromatch@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +mime@^2.0.3: + version "2.4.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" + integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== + +minimatch@^3.0.2, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.1.0, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +minipass@^2.2.1, minipass@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nan@^2.12.1: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +ncp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" + integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= + +needle@^2.2.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" + integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + +node-pre-gyp@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" + integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.0, normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +npm-bundled@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" + integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== + +npm-packlist@^1.1.6: + version "1.4.4" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44" + integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-tmpdir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +progress@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +proxy-from-env@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" + integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4= + +puppeteer@^1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.19.0.tgz#e3b7b448c2c97933517078d7a2c53687361bebea" + integrity sha512-2S6E6ygpoqcECaagDbBopoSOPDv0pAZvTbnBgUY+6hq0/XDFDOLEMNlHF/SKJlzcaZ9ckiKjKDuueWI3FN/WXw== + dependencies: + debug "^4.1.0" + extract-zip "^1.6.6" + https-proxy-agent "^2.2.1" + mime "^2.0.3" + progress "^2.0.1" + proxy-from-env "^1.0.0" + rimraf "^2.6.1" + ws "^6.1.0" + +randomatic@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" + integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== + dependencies: + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" + +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + +readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== + dependencies: + is-equal-shallow "^0.1.3" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.5.2, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.1.7, resolve@^1.10.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" + integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== + dependencies: + path-parse "^1.0.6" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +rimraf@^2.6.1, rimraf@^2.6.3: + version "2.7.0" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.0.tgz#eb43198c5e2fb83b9323abee63bd87836f9a7c85" + integrity sha512-4Liqw7ccABzsWV5BzeZeGRSq7KWIgQYzOcmRDEwSX4WAawlQpcAFXZ1Kid72XYrjSnK5yxOS6Gez/iGusYE/Pw== + dependencies: + glob "^7.1.3" + +rx@2.3.24: + version "2.3.24" + resolved "https://registry.yarnpkg.com/rx/-/rx-2.3.24.tgz#14f950a4217d7e35daa71bbcbe58eff68ea4b2b7" + integrity sha1-FPlQpCF9fjXapxu8vljv9o6ksrc= + +safe-buffer@^5.0.1, safe-buffer@^5.1.2: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +"semver@2 || 3 || 4 || 5", semver@^5.3.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +shell-quote@^1.6.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.1.tgz#3161d969886fb14f9140c65245a5dd19b6f0b06b" + integrity sha512-2kUqeAGnMAu6YrTPX4E3LfxacH9gKljzVjlkUeSqY0soGwK4KLl7TURXCem712tkhBCeeaFP9QK4dKn88s3Icg== + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +spawn-command@^0.0.2-1: + version "0.0.2-1" + resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" + integrity sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A= + +spdx-correct@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +subarg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" + integrity sha1-9izxdYHplrSPyWVpn1TAauJouNI= + dependencies: + minimist "^1.1.0" + +supports-color@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= + dependencies: + has-flag "^1.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +tar@^4: + version "4.4.10" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" + integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.5" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" + +tmp@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.1.0.tgz#ee434a4e22543082e294ba6201dcc6eafefa2877" + integrity sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw== + dependencies: + rimraf "^2.6.3" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +tree-kill@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.1.tgz#5398f374e2f292b9dcc7b2e71e30a5c3bb6c743a" + integrity sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q== + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +typescript@2.9.2: + version "2.9.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c" + integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w== + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +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== + +watch@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/watch/-/watch-1.0.2.tgz#340a717bde765726fa0aa07d721e0147a551df0c" + integrity sha1-NApxe952Vyb6CqB9ch4BR6VR3ww= + dependencies: + exec-sh "^0.2.0" + minimist "^1.2.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +ws@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" + integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + dependencies: + async-limiter "~1.0.0" + +yallist@^3.0.0, yallist@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== + +yauzl@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" + integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU= + dependencies: + fd-slicer "~1.0.1" diff --git a/test/electron/renderer.html b/test/electron/renderer.html index a2d4bcc5ad..38005b2d60 100644 --- a/test/electron/renderer.html +++ b/test/electron/renderer.html @@ -19,9 +19,9 @@ // windows. This we cannot allow as it may crash // the test run. // !!! DO NOT CHANGE !!! - window.open = function () {return null;}; - window.alert = function () {} - window.confirm = function () {} + window.open = function () { throw new Error('window.open() is not supported in tests!'); }; + window.alert = function () { throw new Error('window.alert() is not supported in tests!'); } + window.confirm = function () { throw new Error('window.confirm() is not supported in tests!'); } mocha.setup({ ui: 'tdd', diff --git a/test/smoke/README.md b/test/smoke/README.md index b5be966e51..dc90521195 100644 --- a/test/smoke/README.md +++ b/test/smoke/README.md @@ -5,10 +5,8 @@ Make sure you are on **Node v10.x**. ### Run ```bash -# Compile -cd test/smoke -yarn compile -cd ../.. +# Install Dependencies and Compile +yarn --cwd test/smoke # Dev yarn smoketest @@ -26,7 +24,7 @@ You must always run the smoketest version which matches the release you are test ```bash git checkout release/1.22 -yarn +yarn --cwd test/smoke ``` In addition to the new build to be released you will need the previous stable build so that the smoketest can test the data migration. diff --git a/test/smoke/package.json b/test/smoke/package.json index 185fc07d64..be3067a872 100644 --- a/test/smoke/package.json +++ b/test/smoke/package.json @@ -4,12 +4,8 @@ "main": "./src/main.js", "scripts": { "postinstall": "npm run compile", - "compile": "npm run copy-driver && npm run copy-driver-definition && tsc", - "watch": "concurrently \"npm run watch-driver\" \"npm run watch-driver-definition\" \"tsc --watch\"", - "copy-driver": "cpx src/vscode/driver.js out/vscode", - "watch-driver": "cpx src/vscode/driver.js out/vscode -w", - "copy-driver-definition": "node tools/copy-driver-definition.js", - "watch-driver-definition": "watch \"node tools/copy-driver-definition.js\" ../../src/vs/platform/driver/node", + "compile": "yarn --cwd ../automation compile && tsc", + "watch": "concurrently \"yarn --cwd ../automation watch --preserveWatchOutput\" \"tsc --watch --preserveWatchOutput\"", "mocha": "mocha" }, "devDependencies": { @@ -18,12 +14,9 @@ "@types/mocha": "2.2.41", "@types/ncp": "2.0.1", "@types/node": "^10.14.8", - "@types/puppeteer": "^1.19.0", "@types/rimraf": "2.0.2", - "@types/webdriverio": "4.6.1", "concurrently": "^3.5.1", "cpx": "^1.5.0", - "electron": "4.2.9", "htmlparser2": "^3.9.2", "mkdirp": "^0.5.1", "mocha": "^5.2.0", @@ -36,8 +29,5 @@ "tmp": "0.0.33", "typescript": "2.9.2", "watch": "^1.0.2" - }, - "dependencies": { - "vscode-uri": "^2.0.3" } } diff --git a/test/smoke/src/areas/css/css.test.ts b/test/smoke/src/areas/css/css.test.ts index 850306b074..9214e1c12a 100644 --- a/test/smoke/src/areas/css/css.test.ts +++ b/test/smoke/src/areas/css/css.test.ts @@ -3,8 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Application } from '../../application'; -import { ProblemSeverity, Problems } from '../problems/problems'; +import { Application, ProblemSeverity, Problems } from '../../../../automation'; export function setup() { describe('CSS', () => { @@ -44,4 +43,4 @@ export function setup() { await problems.hideProblemsView(); }); }); -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/debug/debug.test.ts b/test/smoke/src/areas/debug/debug.test.ts index 7f53a9d80b..2e188fbd76 100644 --- a/test/smoke/src/areas/debug/debug.test.ts +++ b/test/smoke/src/areas/debug/debug.test.ts @@ -8,7 +8,7 @@ import * as http from 'http'; import * as path from 'path'; import * as fs from 'fs'; import * as stripJsonComments from 'strip-json-comments'; -import { Application } from '../../application'; +import { Application } from '../../../../automation'; export function setup() { describe('Debug', () => { diff --git a/test/smoke/src/areas/editor/editor.test.ts b/test/smoke/src/areas/editor/editor.test.ts index 25f8e6c555..4987db7b41 100644 --- a/test/smoke/src/areas/editor/editor.test.ts +++ b/test/smoke/src/areas/editor/editor.test.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Application } from '../../application'; +import { Application } from '../../../../automation'; export function setup() { describe('Editor', () => { @@ -67,4 +67,4 @@ export function setup() { await peek.waitForFile('app.js'); }); }); -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/explorer/explorer.test.ts b/test/smoke/src/areas/explorer/explorer.test.ts index 6db58217aa..7a7b04c380 100644 --- a/test/smoke/src/areas/explorer/explorer.test.ts +++ b/test/smoke/src/areas/explorer/explorer.test.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Application } from '../../application'; +import { Application } from '../../../../automation'; export function setup() { describe('Explorer', () => { @@ -37,4 +37,4 @@ export function setup() { await app.code.dispatchKeybinding('escape'); }); }); -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/extensions/extensions.test.ts b/test/smoke/src/areas/extensions/extensions.test.ts index d664cd8108..951781dbb2 100644 --- a/test/smoke/src/areas/extensions/extensions.test.ts +++ b/test/smoke/src/areas/extensions/extensions.test.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Application, Quality } from '../../application'; +import { Application, Quality } from '../../../../automation'; export function setup() { describe('Extensions', () => { @@ -28,4 +28,4 @@ export function setup() { await app.workbench.statusbar.waitForStatusbarText('smoke test', 'VS Code Smoke Test Check'); }); }); -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/git/git.test.ts b/test/smoke/src/areas/git/git.test.ts index 92a1850260..61d251eebd 100644 --- a/test/smoke/src/areas/git/git.test.ts +++ b/test/smoke/src/areas/git/git.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as cp from 'child_process'; -import { Application } from '../../application'; +import { Application } from '../../../../automation'; const DIFF_EDITOR_LINE_INSERT = '.monaco-diff-editor .editor.modified .line-insert'; const SYNC_STATUSBAR = 'div[id="workbench.parts.statusbar"] .statusbar-item[title$="Synchronize Changes"]'; @@ -74,4 +74,4 @@ export function setup() { cp.execSync('git reset --hard origin/master', { cwd: app.workspacePathOrFolder }); }); }); -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/multiroot/multiroot.test.ts b/test/smoke/src/areas/multiroot/multiroot.test.ts index ca98e172aa..1f024d2f9c 100644 --- a/test/smoke/src/areas/multiroot/multiroot.test.ts +++ b/test/smoke/src/areas/multiroot/multiroot.test.ts @@ -5,7 +5,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import { Application } from '../../application'; +import { Application } from '../../../../automation'; function toUri(path: string): string { if (process.platform === 'win32') { @@ -47,8 +47,7 @@ export function setup() { const app = this.app as Application; await app.workbench.quickopen.openQuickOpen('*.*'); - // TODO roblourens: Go to files finds welcome page: issue 74875 - await app.workbench.quickopen.waitForQuickOpenElements(names => names.length === 6 || names.length === 7); + await app.workbench.quickopen.waitForQuickOpenElements(names => names.length === 6); await app.workbench.quickopen.closeQuickOpen(); }); @@ -57,4 +56,4 @@ export function setup() { await app.code.waitForTitle(title => /smoketest \(Workspace\)/i.test(title)); }); }); -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/preferences/preferences.test.ts b/test/smoke/src/areas/preferences/preferences.test.ts index 202d56b03b..337ce724b6 100644 --- a/test/smoke/src/areas/preferences/preferences.test.ts +++ b/test/smoke/src/areas/preferences/preferences.test.ts @@ -3,8 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Application } from '../../application'; -import { ActivityBarPosition } from '../activitybar/activityBar'; +import { Application, ActivityBarPosition } from '../../../../automation'; export function setup() { describe('Preferences', () => { diff --git a/test/smoke/src/areas/search/search.test.ts b/test/smoke/src/areas/search/search.test.ts index 24dfcb5d58..8af936fcdb 100644 --- a/test/smoke/src/areas/search/search.test.ts +++ b/test/smoke/src/areas/search/search.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as cp from 'child_process'; -import { Application } from '../../application'; +import { Application } from '../../../../automation'; export function setup() { describe('Search', () => { @@ -56,4 +56,4 @@ export function setup() { await app.workbench.search.waitForNoResultText(); }); }); -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/statusbar/statusbar.test.ts b/test/smoke/src/areas/statusbar/statusbar.test.ts index c361b1633f..64feccc0d7 100644 --- a/test/smoke/src/areas/statusbar/statusbar.test.ts +++ b/test/smoke/src/areas/statusbar/statusbar.test.ts @@ -3,8 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Application, Quality } from '../../application'; -import { StatusBarElement } from './statusbar'; +import { Application, Quality, StatusBarElement } from '../../../../automation'; export function setup() { describe('Statusbar', () => { @@ -90,4 +89,4 @@ export function setup() { await app.workbench.statusbar.waitForEOL('CRLF'); }); }); -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/terminal/terminal.test.ts b/test/smoke/src/areas/terminal/terminal.test.ts index 0f2ef11a88..7a45d3f15d 100644 --- a/test/smoke/src/areas/terminal/terminal.test.ts +++ b/test/smoke/src/areas/terminal/terminal.test.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Application } from '../../application'; +import { Application } from '../../../../automation'; export function setup() { describe('Terminal', () => { diff --git a/test/smoke/src/areas/workbench/data-loss.test.ts b/test/smoke/src/areas/workbench/data-loss.test.ts index bec56cbe51..7cfce50e04 100644 --- a/test/smoke/src/areas/workbench/data-loss.test.ts +++ b/test/smoke/src/areas/workbench/data-loss.test.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Application } from '../../application'; +import { Application } from '../../../../automation'; export function setup() { describe('Dataloss', () => { diff --git a/test/smoke/src/areas/workbench/data-migration.test.ts b/test/smoke/src/areas/workbench/data-migration.test.ts index 1c7f85c100..3f26636548 100644 --- a/test/smoke/src/areas/workbench/data-migration.test.ts +++ b/test/smoke/src/areas/workbench/data-migration.test.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Application, ApplicationOptions } from '../../application'; +import { Application, ApplicationOptions } from '../../../../automation'; import { join } from 'path'; export function setup(stableCodePath: string, testDataPath: string) { diff --git a/test/smoke/src/areas/workbench/launch.test.ts b/test/smoke/src/areas/workbench/launch.test.ts index 2fa288f9d1..1bd629d415 100644 --- a/test/smoke/src/areas/workbench/launch.test.ts +++ b/test/smoke/src/areas/workbench/launch.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as path from 'path'; -import { Application, ApplicationOptions } from '../../application'; +import { Application, ApplicationOptions } from '../../../../automation'; export function setup() { @@ -35,4 +35,4 @@ export function setup() { }); }); -} \ No newline at end of file +} diff --git a/test/smoke/src/areas/workbench/localization.test.ts b/test/smoke/src/areas/workbench/localization.test.ts index 07c9b8c237..fbc82ab498 100644 --- a/test/smoke/src/areas/workbench/localization.test.ts +++ b/test/smoke/src/areas/workbench/localization.test.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Application, Quality } from '../../application'; +import { Application, Quality } from '../../../../automation'; export function setup() { describe('Localization', () => { diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index 8dc4e2f764..461fee2ebe 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -11,7 +11,15 @@ import * as tmp from 'tmp'; import * as rimraf from 'rimraf'; import * as mkdirp from 'mkdirp'; import { ncp } from 'ncp'; -import { Application, Quality, ApplicationOptions } from './application'; +import { + Application, + Quality, + ApplicationOptions, + MultiLogger, + Logger, + ConsoleLogger, + FileLogger, +} from '../../automation'; //{{SQL CARBON EDIT}} import { setup as runProfilerTests } from './sql/profiler/profiler.test'; @@ -33,10 +41,7 @@ import { setup as setupDataExtensionTests } from './areas/extensions/extensions. import { setup as setupTerminalTests } from './areas/terminal/terminal.test'; import { setup as setupDataMultirootTests } from './areas/multiroot/multiroot.test'; import { setup as setupDataLocalizationTests } from './areas/workbench/localization.test'; -import { setup as setupLaunchTests } from './areas/workbench/launch.test'; -*/ -//{{END}} -import { MultiLogger, Logger, ConsoleLogger, FileLogger } from './logger'; +import { setup as setupLaunchTests } from './areas/workbench/launch.test';*///{{END}} if (!/^v10/.test(process.version)) { console.error('Error: Smoketest must be run using Node 10. Currently running', process.version); diff --git a/test/smoke/src/sql/profiler/profiler.test.ts b/test/smoke/src/sql/profiler/profiler.test.ts index b72370f5a8..c96b2004ed 100644 --- a/test/smoke/src/sql/profiler/profiler.test.ts +++ b/test/smoke/src/sql/profiler/profiler.test.ts @@ -3,8 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Application } from '../../application'; -import { getStandaloneServer } from '../testConfig'; +import { Application, getStandaloneServer } from '../../../../automation'; export function setup() { describe('profiler test suite', () => { @@ -16,4 +15,4 @@ export function setup() { await app.workbench.profiler.waitForNewSessionDialogAndStart(); }); }); -} \ No newline at end of file +} diff --git a/test/smoke/src/sql/queryEditor/queryEditor.test.ts b/test/smoke/src/sql/queryEditor/queryEditor.test.ts index e2b6130234..98e0344c74 100644 --- a/test/smoke/src/sql/queryEditor/queryEditor.test.ts +++ b/test/smoke/src/sql/queryEditor/queryEditor.test.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Application } from '../../application'; +import { Application } from '../../../../automation'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; @@ -25,4 +25,4 @@ export function setup() { } }); }); -} \ No newline at end of file +} diff --git a/test/smoke/tsconfig.json b/test/smoke/tsconfig.json index 1b0b03c2d6..6f0b40e93e 100644 --- a/test/smoke/tsconfig.json +++ b/test/smoke/tsconfig.json @@ -4,7 +4,7 @@ "noImplicitAny": false, "removeComments": false, "preserveConstEnums": true, - "target": "es2016", + "target": "es2017", "strictNullChecks": true, "noUnusedParameters": false, "noUnusedLocals": true, @@ -18,4 +18,4 @@ "exclude": [ "node_modules" ] -} \ No newline at end of file +} diff --git a/test/smoke/yarn.lock b/test/smoke/yarn.lock index 5219fecf77..221596fc2c 100644 --- a/test/smoke/yarn.lock +++ b/test/smoke/yarn.lock @@ -44,23 +44,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb" integrity sha512-El3+WJk2D/ppWNd2X05aiP5l2k4EwF7KwheknQZls+I26eSICoWRhRIJ56jGgw2dqNGQ5LtNajmBU2ajS28EvQ== -"@types/node@^10.12.18": - version "10.12.18" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" - integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ== - "@types/node@^10.14.8": version "10.14.8" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== -"@types/puppeteer@^1.19.0": - version "1.19.0" - resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-1.19.0.tgz#59f0050bae019cee7c3af2bb840a25892a3078b6" - integrity sha512-Db9LWOuTm2bR/qgPE7PQCmnsCQ6flHdULuIDWTks8YdQ/SGHKg5WGWG54gl0734NDKCTF5MbqAp2qWuvBiyQ3Q== - dependencies: - "@types/node" "*" - "@types/rimraf@2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.2.tgz#7f0fc3cf0ff0ad2a99bb723ae1764f30acaf8b6e" @@ -69,28 +57,11 @@ "@types/glob" "*" "@types/node" "*" -"@types/webdriverio@4.6.1": - version "4.6.1" - resolved "https://registry.yarnpkg.com/@types/webdriverio/-/webdriverio-4.6.1.tgz#5143c222e465425f0119668eb1e1276696567800" - integrity sha1-UUPCIuRlQl8BGWaOseEnZpZWeAA= - dependencies: - "@types/node" "*" - abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -ajv@^5.1.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.3.0.tgz#4414ff74a50879c208ee5fdc826e32c303549eda" - integrity sha1-RBT/dKUIecII7l/cgm4ywwNUnto= - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" @@ -159,11 +130,6 @@ array-filter@~0.0.0: resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" integrity sha1-fajPLiZijtcygDWB/SH2fKzS7uw= -array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= - array-map@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" @@ -184,16 +150,6 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - integrity sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y= - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" @@ -204,26 +160,11 @@ async-each@^1.0.0: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - atob@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" - integrity sha1-g+9cqGCysy5KDe7e6MdxudtXRx4= - babel-runtime@^6.9.2: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" @@ -250,13 +191,6 @@ base@^0.11.1: mixin-deep "^1.2.0" pascalcase "^0.1.1" -bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - integrity sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40= - dependencies: - tweetnacl "^0.14.3" - binary-extensions@^1.0.0: version "1.13.1" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" @@ -267,20 +201,6 @@ bluebird@^2.9.34: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE= -boom@4.x.x: - version "4.3.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" - integrity sha1-T4owBctKfjiJ90kDD9JbluAdLjE= - dependencies: - hoek "4.x.x" - -boom@5.x.x: - version "5.2.0" - resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" - integrity sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw== - dependencies: - hoek "4.x.x" - brace-expansion@^1.1.7: version "1.1.8" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" @@ -319,11 +239,6 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== -builtin-modules@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= - cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -339,24 +254,6 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - -camelcase@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - chalk@0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" @@ -404,11 +301,6 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" @@ -422,13 +314,6 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" - integrity sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk= - dependencies: - delayed-stream "~1.0.0" - commander@2.15.1: version "2.15.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" @@ -454,15 +339,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" - integrity sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc= - dependencies: - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - concurrently@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-3.5.1.tgz#ee8b60018bbe86b02df13e5249453c6ececd2521" @@ -492,7 +368,7 @@ core-js@^2.4.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== -core-util-is@1.0.2, core-util-is@~1.0.0: +core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= @@ -519,39 +395,11 @@ crypt@~0.0.1: resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= -cryptiles@3.x.x: - version "3.1.2" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" - integrity sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4= - dependencies: - boom "5.x.x" - -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= - dependencies: - array-find-index "^1.0.1" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - date-fns@^1.23.0: version "1.29.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" integrity sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw== -debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - debug@3.1.0, debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" @@ -559,18 +407,20 @@ debug@3.1.0, debug@^3.1.0: dependencies: ms "2.0.0" -debug@^3.0.0, debug@^3.2.6: +debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== dependencies: ms "^2.1.1" -decamelize@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -603,11 +453,6 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -661,54 +506,11 @@ duplexer@^0.1.1: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= -ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - integrity sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU= - dependencies: - jsbn "~0.1.0" - -electron-download@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-4.1.1.tgz#02e69556705cc456e520f9e035556ed5a015ebe8" - integrity sha512-FjEWG9Jb/ppK/2zToP+U5dds114fM1ZOJqMAR4aXXL5CvyPE9fiqBK/9YcwC9poIFQTEJk/EM/zyRwziziRZrg== - dependencies: - debug "^3.0.0" - env-paths "^1.0.0" - fs-extra "^4.0.1" - minimist "^1.2.0" - nugget "^2.0.1" - path-exists "^3.0.0" - rc "^1.2.1" - semver "^5.4.1" - sumchecker "^2.0.2" - -electron@4.2.9: - version "4.2.9" - resolved "https://registry.yarnpkg.com/electron/-/electron-4.2.9.tgz#81226aa1ba58e1b05388474faf5a815010a11ea2" - integrity sha512-zC7K3GOiZKmxqllVG/qq/Gx+qQvyolKj5xKKwXMqIGekfokEW2hvoIO5Yh7KCoAh5dqBtpzOJjS4fj1se+YBcg== - dependencies: - "@types/node" "^10.12.18" - electron-download "^4.1.0" - extract-zip "^1.0.3" - entities@^1.1.1, entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA= -env-paths@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-1.0.0.tgz#4168133b42bb05c38a35b1ae4397c8298ab369e0" - integrity sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA= - -error-ex@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" - integrity sha1-+FWobOYa3E6GIcPNoh56dhLDqNw= - dependencies: - is-arrayish "^0.2.1" - escape-string-regexp@1.0.5, escape-string-regexp@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -763,11 +565,6 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@~3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" - integrity sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ= - extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" @@ -789,38 +586,6 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-zip@^1.0.3: - version "1.6.6" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c" - integrity sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw= - dependencies: - concat-stream "1.6.0" - debug "2.6.9" - mkdirp "0.5.0" - yauzl "2.4.1" - -extsprintf@1.3.0, extsprintf@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -fast-deep-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" - integrity sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8= - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= - -fd-slicer@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" - integrity sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU= - dependencies: - pend "~1.2.0" - filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" @@ -852,14 +617,6 @@ find-index@^0.1.1: resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" integrity sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ= -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -872,20 +629,6 @@ for-own@^0.1.4: dependencies: for-in "^1.0.1" -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data@~2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" - integrity sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8= - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" @@ -893,15 +636,6 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -fs-extra@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" - integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-minipass@^1.2.5: version "1.2.6" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" @@ -936,23 +670,11 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= - get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" @@ -992,29 +714,11 @@ graceful-fs@^4.1.11: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== -graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= - growl@1.10.5: version "1.10.5" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" - integrity sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0= - dependencies: - ajv "^5.1.0" - har-schema "^2.0.0" - has-ansi@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" @@ -1068,31 +772,11 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -hawk@~6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" - integrity sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ== - dependencies: - boom "4.x.x" - cryptiles "3.x.x" - hoek "4.x.x" - sntp "2.x.x" - he@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= -hoek@4.x.x: - version "4.2.0" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" - integrity sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ== - -hosted-git-info@^2.1.4: - version "2.5.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" - integrity sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg== - htmlparser2@^3.9.2: version "3.9.2" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" @@ -1105,15 +789,6 @@ htmlparser2@^3.9.2: inherits "^2.0.1" readable-stream "^2.0.2" -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -1128,13 +803,6 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= - dependencies: - repeating "^2.0.0" - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -1143,7 +811,7 @@ 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, 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= @@ -1167,11 +835,6 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" @@ -1184,13 +847,6 @@ is-buffer@^1.1.5, is-buffer@~1.1.1: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-builtin-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= - dependencies: - builtin-modules "^1.0.0" - is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -1252,13 +908,6 @@ is-extglob@^1.0.0: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= -is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= - dependencies: - number-is-nan "^1.0.0" - is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" @@ -1314,26 +963,11 @@ is-primitive@^2.0.0: resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= - is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -1351,53 +985,11 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -1422,17 +1014,6 @@ kind-of@^6.0.0, kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - lodash@^4.16.4: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -1443,24 +1024,11 @@ lodash@^4.5.1: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" integrity sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw== -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= -map-obj@^1.0.0, map-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= - map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" @@ -1482,22 +1050,6 @@ md5@^2.1.0: crypt "~0.0.1" is-buffer "~1.1.1" -meow@^3.1.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" - merge@^1.1.3: version "1.2.0" resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" @@ -1541,18 +1093,6 @@ micromatch@^3.1.10: snapdragon "^0.8.1" to-regex "^3.0.2" -mime-db@~1.30.0: - version "1.30.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" - integrity sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE= - -mime-types@^2.1.12, mime-types@~2.1.17: - version "2.1.17" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" - integrity sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo= - dependencies: - mime-db "~1.30.0" - minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -1565,7 +1105,7 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: +minimist@^1.1.0, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= @@ -1593,13 +1133,6 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" - integrity sha1-HXMHam35hs2TROFecfzAWkyavxI= - dependencies: - minimist "0.0.8" - mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -1713,16 +1246,6 @@ nopt@^4.0.1: abbrev "1" osenv "^0.1.4" -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: - version "2.4.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" - integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw== - dependencies: - hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - normalize-path@^2.0.0, normalize-path@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" @@ -1753,30 +1276,12 @@ npmlog@^4.0.2: gauge "~2.7.3" set-blocking "~2.0.0" -nugget@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/nugget/-/nugget-2.0.1.tgz#201095a487e1ad36081b3432fa3cada4f8d071b0" - integrity sha1-IBCVpIfhrTYIGzQy+jytpPjQcbA= - dependencies: - debug "^2.1.3" - minimist "^1.1.0" - pretty-bytes "^1.0.2" - progress-stream "^1.1.0" - request "^2.45.0" - single-line-log "^1.1.2" - throttleit "0.0.2" - number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -oauth-sign@~0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM= - -object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -1790,11 +1295,6 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-keys@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" - integrity sha1-KKaq50KN0sOpLz2V8hM13SBOAzY= - object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" @@ -1852,30 +1352,11 @@ parse-glob@^3.0.4: is-extglob "^1.0.0" is-glob "^2.0.0" -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= - dependencies: - pinkie-promise "^2.0.0" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -1886,42 +1367,6 @@ path-parse@^1.0.6: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - portastic@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/portastic/-/portastic-1.0.1.tgz#1c9805d43fae8f6a40cf0dbc7794091a2e9d0d2a" @@ -1941,14 +1386,6 @@ preserve@^0.2.0: resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= -pretty-bytes@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-1.0.4.tgz#0a22e8210609ad35542f8c8d5d2159aff0751c84" - integrity sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ= - dependencies: - get-stdin "^4.0.1" - meow "^3.1.0" - process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" @@ -1959,24 +1396,6 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -progress-stream@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/progress-stream/-/progress-stream-1.2.0.tgz#2cd3cfea33ba3a89c9c121ec3347abe9ab125f77" - integrity sha1-LNPP6jO6OonJwSHsM0er6asSX3c= - dependencies: - speedometer "~0.1.2" - through2 "~0.2.3" - -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -qs@~6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" - integrity sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A== - randomatic@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" @@ -1986,7 +1405,7 @@ randomatic@^3.0.0: kind-of "^6.0.0" math-random "^1.0.1" -rc@^1.2.1, rc@^1.2.7: +rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -1996,24 +1415,7 @@ rc@^1.2.1, rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - -readable-stream@^2.0.2, readable-stream@^2.2.2: +readable-stream@^2.0.2: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" integrity sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ== @@ -2039,16 +1441,6 @@ readable-stream@^2.0.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@~1.1.9: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - readdirp@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -2058,14 +1450,6 @@ readdirp@^2.0.0: micromatch "^3.1.10" readable-stream "^2.0.2" -redent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" @@ -2101,41 +1485,6 @@ repeat-string@^1.5.2, repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= - dependencies: - is-finite "^1.0.0" - -request@^2.45.0: - version "2.83.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" - integrity sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - hawk "~6.0.2" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - stringstream "~0.0.5" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -2165,7 +1514,7 @@ rx@2.3.24: resolved "https://registry.yarnpkg.com/rx/-/rx-2.3.24.tgz#14f950a4217d7e35daa71bbcbe58eff68ea4b2b7" integrity sha1-FPlQpCF9fjXapxu8vljv9o6ksrc= -safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== @@ -2192,21 +1541,11 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -"semver@2 || 3 || 4 || 5": - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - integrity sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg== - semver@^5.3.0: version "5.7.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== -semver@^5.4.1: - version "5.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" - integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== - set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -2237,13 +1576,6 @@ signal-exit@^3.0.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= -single-line-log@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/single-line-log/-/single-line-log-1.1.2.tgz#c2f83f273a3e1a16edb0995661da0ed5ef033364" - integrity sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q= - dependencies: - string-width "^1.0.1" - snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -2274,13 +1606,6 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -sntp@2.x.x: - version "2.1.0" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" - integrity sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg== - dependencies: - hoek "4.x.x" - source-map-resolve@^0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" @@ -2307,28 +1632,6 @@ spawn-command@^0.0.2-1: resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" integrity sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A= -spdx-correct@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" - integrity sha1-SzBz2TP/UfORLwOsVRlJikFQ20A= - dependencies: - spdx-license-ids "^1.0.2" - -spdx-expression-parse@~1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" - integrity sha1-m98vIOH0DtRH++JzJmGR/O1RYmw= - -spdx-license-ids@^1.0.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" - integrity sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc= - -speedometer@~0.1.2: - version "0.1.4" - resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d" - integrity sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0= - split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -2336,21 +1639,6 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" -sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" - integrity sha1-US322mKHFEMW3EwY/hzx2UBzm+M= - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jsbn "~0.1.0" - tweetnacl "~0.14.0" - static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -2376,11 +1664,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - string_decoder@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" @@ -2395,11 +1678,6 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -stringstream@~0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - integrity sha1-TkhM1N5aC7vuGORjB3EKioFiGHg= - strip-ansi@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" @@ -2421,20 +1699,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= - dependencies: - is-utf8 "^0.2.0" - -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= - dependencies: - get-stdin "^4.0.1" - strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -2447,13 +1711,6 @@ subarg@^1.0.0: dependencies: minimist "^1.1.0" -sumchecker@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-2.0.2.tgz#0f42c10e5d05da5d42eea3e56c3399a37d6c5b3e" - integrity sha1-D0LBDl0F2l1C7qPlbDOZo31sWz4= - dependencies: - debug "^2.2.0" - supports-color@5.4.0: version "5.4.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" @@ -2486,19 +1743,6 @@ tar@^4: safe-buffer "^5.1.2" yallist "^3.0.3" -throttleit@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf" - integrity sha1-z+34jmDADdlpe2H90qg0OptoDq8= - -through2@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-0.2.3.tgz#eb3284da4ea311b6cc8ace3653748a52abf25a3f" - integrity sha1-6zKE2k6jEbbMis42U3SKUqvyWj8= - dependencies: - readable-stream "~1.1.9" - xtend "~2.1.1" - tmp@0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -2531,40 +1775,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" -tough-cookie@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" - integrity sha1-C2GKVWW23qkL80JdBNVe3EdadWE= - dependencies: - punycode "^1.4.1" - tree-kill@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36" integrity sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg== -trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - typescript@2.9.2: version "2.9.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c" @@ -2580,11 +1795,6 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^2.0.1" -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" @@ -2608,33 +1818,6 @@ util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -uuid@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" - integrity sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g== - -validate-npm-package-license@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" - integrity sha1-KAS6vnEq0zeUWaz74kdGqywwP7w= - dependencies: - spdx-correct "~1.0.0" - spdx-expression-parse "~1.0.0" - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -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== - watch@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/watch/-/watch-1.0.2.tgz#340a717bde765726fa0aa07d721e0147a551df0c" @@ -2660,21 +1843,7 @@ xml@^1.0.0: resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= -xtend@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" - integrity sha1-bv7MKk2tjmlixJAbM3znuoe10os= - dependencies: - object-keys "~0.4.0" - yallist@^3.0.0, yallist@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== - -yauzl@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" - integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU= - dependencies: - fd-slicer "~1.0.1" diff --git a/test/tree/public/index.html b/test/tree/public/index.html index 17c88461c4..3f66d50501 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/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 }) => { + require(['vs/base/browser/ui/tree/indexTree', 'vs/base/browser/ui/tree/objectTree', 'vs/base/browser/ui/tree/asyncDataTree', 'vs/base/browser/ui/tree/dataTree', 'vs/base/browser/ui/tree/tree', 'vs/base/common/iterator'], ({ IndexTree }, { CompressibleObjectTree }, { AsyncDataTree }, { DataTree }, { TreeVisibility }, { iter }) => { function createIndexTree(opts) { opts = opts || {}; @@ -95,7 +95,7 @@ } }; - const tree = new IndexTree(container, delegate, [renderer], null, { ...opts, filter: treeFilter, setRowLineHeight: false }); + const tree = new IndexTree('test', container, delegate, [renderer], null, { ...opts, filter: treeFilter, setRowLineHeight: false }); return { tree, treeFilter }; } @@ -113,11 +113,10 @@ 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; - } + container.innerHTML = element.element.name; + }, + renderCompressedElements(node, index, container, height) { + container.innerHTML = `🙈 ${node.element.elements.map(el => el.name).join('/')}`; }, disposeElement() { }, disposeTemplate() { } @@ -146,7 +145,7 @@ } }; - const tree = new CompressedObjectTree(container, delegate, [renderer], { ...opts, filter: treeFilter, setRowLineHeight: false, collapseByDefault: true, setRowLineHeight: true }); + const tree = new CompressibleObjectTree('test', container, delegate, [renderer], { ...opts, filter: treeFilter, setRowLineHeight: false, collapseByDefault: true, setRowLineHeight: true }); return { tree, treeFilter }; } @@ -206,7 +205,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) { @@ -228,7 +227,7 @@ } }; - const tree = new AsyncDataTree(container, delegate, [renderer], dataSource, { filter: treeFilter, sorter, identityProvider }); + const tree = new AsyncDataTree('test', container, delegate, [renderer], dataSource, { filter: treeFilter, sorter, identityProvider }); return { tree, treeFilter }; } @@ -283,15 +282,15 @@ } }; - const tree = new DataTree(container, delegate, [renderer], dataSource, { filter: treeFilter, identityProvider }); + const tree = new DataTree('test', container, delegate, [renderer], dataSource, { filter: treeFilter, identityProvider }); - tree.input = { + tree.setInput({ children: [ { name: 'A', children: [{ name: 'AA' }, { name: 'AB' }] }, { name: 'B', children: [{ name: 'BA', children: [{ name: 'BAA' }] }, { name: 'BB' }] }, { name: 'C' } ] - }; + }); return { tree, treeFilter }; } @@ -324,9 +323,9 @@ expandall.onclick = () => perf('expand all', () => tree.expandAll()); collapseall.onclick = () => perf('collapse all', () => tree.collapseAll()); renderwidth.onclick = () => perf('renderwidth', () => tree.layoutWidth(Math.random())); - refresh.onclick = () => perf('refresh', () => tree.refresh(null, true)); + refresh.onclick = () => perf('refresh', () => tree.updateChildren()); - tree.refresh(null); + tree.setInput(null); break; } @@ -336,7 +335,7 @@ expandall.onclick = () => perf('expand all', () => tree.expandAll()); collapseall.onclick = () => perf('collapse all', () => tree.collapseAll()); renderwidth.onclick = () => perf('renderwidth', () => tree.layoutWidth(Math.random())); - refresh.onclick = () => perf('refresh', () => tree.refresh(null, true)); + refresh.onclick = () => perf('refresh', () => tree.updateChildren()); break; } @@ -401,4 +400,4 @@ - \ No newline at end of file + diff --git a/yarn.lock b/yarn.lock index a236ffbb94..434c1b0ba5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -489,33 +489,16 @@ acorn-dynamic-import@^3.0.0: dependencies: acorn "^5.0.0" -acorn-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" - integrity sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s= - dependencies: - acorn "^3.0.4" - acorn-jsx@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== -acorn@^3.0.4: - version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - integrity sha1-ReN/s56No/JbruP/U2niu18iAXo= - acorn@^5.0.0, acorn@^5.6.2: version "5.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" integrity sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ== -acorn@^5.5.0: - version "5.7.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" - integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== - acorn@^6.0.2: version "6.0.7" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.7.tgz#490180ce18337270232d9488a44be83d9afb7fd3" @@ -535,11 +518,6 @@ agent-base@~4.2.0: dependencies: es6-promisify "^5.0.0" -ajv-keywords@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" - integrity sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I= - ajv-keywords@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" @@ -555,7 +533,7 @@ ajv@^5.1.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ajv@^5.2.3, ajv@^5.3.0: +ajv@^5.3.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= @@ -623,11 +601,6 @@ ansi-cyan@^0.1.1: dependencies: ansi-wrap "0.1.0" -ansi-escapes@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" - integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw== - ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" @@ -809,11 +782,6 @@ array-each@^1.0.0, array-each@^1.0.1: resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f" integrity sha1-p5SvDAWrF1KEbudTofIRoFugxE8= -array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -962,11 +930,6 @@ async-settle@^1.0.0: dependencies: async-done "^1.2.2" -async@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= - async@^2.1.5: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" @@ -1033,15 +996,6 @@ azure-storage@^2.10.2: xml2js "0.2.8" xmlbuilder "^9.0.7" -babel-code-frame@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - bach@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/bach/-/bach-1.2.0.tgz#4b3ce96bf27134f79a1b414a51c14e34c3bd9880" @@ -1102,6 +1056,11 @@ big.js@^3.1.3: resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + binary-extensions@^1.0.0: version "1.10.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" @@ -1420,46 +1379,16 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8= - dependencies: - callsites "^0.2.0" - -callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo= - callsites@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3" integrity sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw== -camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - -camelcase@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= - camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= -camelcase@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= - camelcase@^5.0.0: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -1506,6 +1435,15 @@ chalk@2.3.1: escape-string-regexp "^1.0.5" supports-color "^5.2.0" +chalk@2.4.2, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -1517,7 +1455,7 @@ chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.4.1: +chalk@^2.0.0: version "2.4.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== @@ -1526,15 +1464,6 @@ chalk@^2.0.0, chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^2.1.0, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - chalk@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" @@ -1544,16 +1473,6 @@ chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^4.0.0" -chardet@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" - integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= - -chardet@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.5.0.tgz#fe3ac73c00c3d865ffcc02a0682e2c20b6a06029" - integrity sha512-9ZTaoBaePSCFvNlNGrsyI8ZVACP2svUtq0DkM7t4K2ClAa96sqOIRjAzDTc8zXzFt1cZR46rRzLTiHFSJ+Qw0g== - chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -1663,11 +1582,6 @@ chromium-pickle-js@^0.2.0: resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz#04a106672c18b085ab774d983dfa3ea138f22205" integrity sha1-BKEGZywYsIWrd02YPfo+oTjyIgU= -ci-info@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.1.tgz#47b44df118c48d2597b56d342e7e25791060171a" - integrity sha512-vHDDF/bP9RYpTWtUhpJRhCFdvvp3iDWvEbuDbWgvjUrNGV1MXJrE0MPcwGtEled04m61iwdBLUIHZtDgzWS4ZQ== - cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -1719,15 +1633,6 @@ cliui@^3.2.0: strip-ansi "^3.0.1" wrap-ansi "^2.0.0" -cliui@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.0.0.tgz#743d4650e05f36d1ed2575b59638d87322bfbbcc" - integrity sha512-nY3W5Gu2racvdDk//ELReY+dHjb9PlIcVDFXP72nVIhq2Gy3LuVXYwJoPVudwQnv1shtohpgkdCKT2YaKY0CKw== - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" - cliui@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" @@ -1857,11 +1762,6 @@ colormin@^1.0.5: css-color-names "0.0.4" has "^1.0.1" -colors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= - colors@^1.1.2: version "1.2.1" resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.1.tgz#f4a3d302976aaf042356ba1ade3b1a2c62d9d794" @@ -1903,7 +1803,7 @@ commander@0.6.1: resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" integrity sha1-+mihT2qUXVTbvlDYzbMyDp47GgY= -commander@2.11.x, commander@^2.8.1, commander@^2.9.0, commander@~2.11.0: +commander@2.11.x, commander@^2.8.1, commander@^2.9.0: version "2.11.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== @@ -1948,16 +1848,7 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" - integrity sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc= - dependencies: - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -concat-stream@1.6.2, concat-stream@^1.5.0, concat-stream@^1.6.0: +concat-stream@^1.5.0, concat-stream@^1.6.0: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -2075,11 +1966,6 @@ core-util-is@1.0.2, core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -corser@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87" - integrity sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c= - coveralls@^2.11.11: version "2.13.3" resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-2.13.3.tgz#9ad7c2ae527417f361e8b626483f48ee92dd2bc7" @@ -2122,16 +2008,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-spawn@^5.0.1, cross-spawn@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^6.0.0, cross-spawn@^6.0.5: +cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -2268,13 +2145,6 @@ cuint@^0.2.1: resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b" integrity sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs= -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= - dependencies: - array-find-index "^1.0.1" - cyclist@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" @@ -2311,7 +2181,7 @@ debug@2.2.0: dependencies: ms "0.7.1" -debug@2.6.9, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3: +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -2325,7 +2195,7 @@ debug@3.1.0: dependencies: ms "2.0.0" -debug@^3.1.0, debug@^3.2.6: +debug@^3.1.0: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -2344,13 +2214,6 @@ decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= -decamelize@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7" - integrity sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg== - dependencies: - xregexp "4.0.0" - decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -2381,11 +2244,6 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-extend@~0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" - integrity sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8= - deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -2617,7 +2475,7 @@ domutils@^1.5.1: dom-serializer "0" domelementtype "1" -duplexer@~0.1.1: +duplexer@^0.1.1, duplexer@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= @@ -2657,16 +2515,6 @@ ecc-jsbn@~0.1.1: dependencies: jsbn "~0.1.0" -ecstatic@^3.0.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.1.tgz#b15b5b036c2233defc78d7bacbd8765226c95577" - integrity sha512-/rrctvxZ78HMI/tPIsqdvFKHHscxR3IJuKrZI2ZoUgkt2SiufyLFBmcco+aqQBIu6P1qBsUNG3drAAGLx80vTQ== - dependencies: - he "^1.1.1" - mime "^1.6.0" - minimist "^1.1.0" - url-join "^2.0.5" - editorconfig@^0.15.0: version "0.15.0" resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.0.tgz#b6dd4a0b6b9e76ce48e066bdc15381aebb8804fd" @@ -2696,29 +2544,6 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-download@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-4.1.0.tgz#bf932c746f2f87ffcc09d1dd472f2ff6b9187845" - integrity sha1-v5MsdG8vh//MCdHdRy8v9rkYeEU= - dependencies: - debug "^2.2.0" - env-paths "^1.0.0" - fs-extra "^2.0.0" - minimist "^1.2.0" - nugget "^2.0.0" - path-exists "^3.0.0" - rc "^1.1.2" - semver "^5.3.0" - sumchecker "^2.0.1" - -electron-mksnapshot@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/electron-mksnapshot/-/electron-mksnapshot-2.0.0.tgz#c7a9e95b86693fdfe60ea7b65df6c237009e4be8" - integrity sha512-OoZwZJNKgHP+DwhCGVTJEuDSeb478hOzAbHeg7dKGCHDbKKmUWmjGc+pEjxGutpqQ3Mn8hCdLzdx2c/lAJcTLA== - dependencies: - electron-download "^4.1.0" - extract-zip "^1.6.5" - electron-to-chromium@^1.2.7: version "1.3.27" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.27.tgz#78ecb8a399066187bb374eede35d9c70565a803d" @@ -2759,7 +2584,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: +enhanced-resolve@4.1.0, enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== @@ -2773,11 +2598,6 @@ entities@^1.1.1, entities@~1.1.1: resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA= -env-paths@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-1.0.0.tgz#4168133b42bb05c38a35b1ae4397c8298ab369e0" - integrity sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA= - errno@^0.1.3, errno@~0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" @@ -2854,14 +2674,6 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -eslint-scope@^3.7.1: - version "3.7.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535" - integrity sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - eslint-scope@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" @@ -2880,50 +2692,6 @@ eslint-visitor-keys@^1.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== -eslint@^4.18.2: - version "4.19.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" - integrity sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ== - dependencies: - ajv "^5.3.0" - babel-code-frame "^6.22.0" - chalk "^2.1.0" - concat-stream "^1.6.0" - cross-spawn "^5.1.0" - debug "^3.1.0" - doctrine "^2.1.0" - eslint-scope "^3.7.1" - eslint-visitor-keys "^1.0.0" - espree "^3.5.4" - esquery "^1.0.0" - esutils "^2.0.2" - file-entry-cache "^2.0.0" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.0.1" - ignore "^3.3.3" - imurmurhash "^0.1.4" - inquirer "^3.0.6" - is-resolvable "^1.0.0" - js-yaml "^3.9.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.4" - minimatch "^3.0.2" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - pluralize "^7.0.0" - progress "^2.0.0" - regexpp "^1.0.1" - require-uncached "^1.0.3" - semver "^5.3.0" - strip-ansi "^4.0.0" - strip-json-comments "~2.0.1" - table "4.0.2" - text-table "~0.2.0" - eslint@^5.0.1: version "5.13.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.13.0.tgz#ce71cc529c450eed9504530939aa97527861ede9" @@ -2966,14 +2734,6 @@ eslint@^5.0.1: table "^5.0.2" text-table "^0.2.0" -espree@^3.5.4: - version "3.5.4" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" - integrity sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A== - dependencies: - acorn "^5.5.0" - acorn-jsx "^3.0.0" - espree@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.0.tgz#fc7f984b62b36a0f543b13fb9cd7b9f4a7f5b65c" @@ -2993,7 +2753,7 @@ esprima@^4.0.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" integrity sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw== -esquery@^1.0.0, esquery@^1.0.1: +esquery@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== @@ -3023,7 +2783,7 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -event-stream@3.3.4, event-stream@^3.3.4, event-stream@~3.3.4: +event-stream@3.3.4, event-stream@^3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" integrity sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE= @@ -3036,10 +2796,18 @@ event-stream@3.3.4, event-stream@^3.3.4, event-stream@~3.3.4: stream-combiner "~0.0.4" through "~2.3.1" -eventemitter3@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" - integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== +event-stream@~3.3.4: + version "3.3.5" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.5.tgz#e5dd8989543630d94c6cf4d657120341fa31636b" + integrity sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g== + dependencies: + duplexer "^0.1.1" + from "^0.1.7" + map-stream "0.0.7" + pause-stream "^0.0.11" + split "^1.0.1" + stream-combiner "^0.2.2" + through "^2.3.8" events@^1.0.0: version "1.1.1" @@ -3054,19 +2822,6 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - execa@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" @@ -3187,24 +2942,6 @@ extend@^3.0.2, extend@~3.0.0, extend@~3.0.2: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -external-editor@^2.0.4: - version "2.2.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" - integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A== - dependencies: - chardet "^0.4.0" - iconv-lite "^0.4.17" - tmp "^0.0.33" - -external-editor@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.0.tgz#dc35c48c6f98a30ca27a20e9687d7f3c77704bb6" - integrity sha512-mpkfj0FEdxrIhOC04zk85X7StNtr0yXnG7zCb+8ikO8OJi2jsHh5YGoknNTyXgsbHOf1WOOcVU3kPFWT2WgCkQ== - dependencies: - chardet "^0.5.0" - iconv-lite "^0.4.22" - tmp "^0.0.33" - external-editor@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" @@ -3235,26 +2972,6 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-zip@^1.6.5: - version "1.6.6" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c" - integrity sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw= - dependencies: - concat-stream "1.6.0" - debug "2.6.9" - mkdirp "0.5.0" - yauzl "2.4.1" - -extract-zip@^1.6.6: - version "1.6.7" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" - integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k= - dependencies: - concat-stream "1.6.2" - debug "2.6.9" - mkdirp "0.5.1" - yauzl "2.4.1" - extsprintf@1.3.0, extsprintf@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -3386,11 +3103,6 @@ find-cache-dir@^1.0.0: make-dir "^1.0.0" pkg-dir "^2.0.0" -find-parent-dir@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.0.tgz#33c44b429ab2b2f0646299c5f9f718f376ff8d54" - integrity sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ= - find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" @@ -3413,6 +3125,16 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" +findup-sync@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" + integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== + dependencies: + detect-file "^1.0.0" + is-glob "^4.0.0" + micromatch "^3.0.4" + resolve-dir "^1.0.1" + findup-sync@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" @@ -3467,13 +3189,6 @@ flush-write-stream@^1.0.0, flush-write-stream@^1.0.2: inherits "^2.0.1" readable-stream "^2.0.4" -follow-redirects@^1.0.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" - integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ== - dependencies: - debug "^3.2.6" - for-in@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.5.tgz#007374e2b6d5c67420a1479bdb75a04872b738c4" @@ -3562,7 +3277,7 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" -from@~0: +from@^0.1.7, from@~0: version "0.1.7" resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= @@ -3583,14 +3298,6 @@ fs-extra@0.26.7: path-is-absolute "^1.0.0" rimraf "^2.2.8" -fs-extra@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" - integrity sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU= - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - fs-extra@^7.0.0: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -3704,16 +3411,6 @@ get-caller-file@^2.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= - -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - get-stream@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -3867,10 +3564,12 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -global-modules-path@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/global-modules-path/-/global-modules-path-2.3.0.tgz#b0e2bac6beac39745f7db5c59d26a36a0b94f7dc" - integrity sha512-HchvMJNYh9dGSCy8pOQ2O8u/hoXaL+0XhnrwH0RyLiSXMMTl9W3N6KUU73+JFOg5PGjtzl6VZzUQsnrpm7Szag== +global-modules@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" global-modules@^1.0.0: version "1.0.0" @@ -3892,7 +3591,16 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" -globals@^11.0.1, globals@^11.1.0: +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== @@ -4147,10 +3855,10 @@ gulp-symdest@^1.1.1: queue "^3.1.0" vinyl-fs "^2.4.3" -gulp-tsb@2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/gulp-tsb/-/gulp-tsb-2.0.7.tgz#0e8c5cc20643d304979a59e90a6448260b314eba" - integrity sha512-9cllqseEkotum/aWHnCTQX/ATD3kyEi1aVzkGp0AEe768uNuU1DqPzRxvyVrfuIPcdYUUvtvmKvEvgIMffNmNA== +gulp-tsb@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/gulp-tsb/-/gulp-tsb-4.0.2.tgz#8717a18f1ce032147e010028f0a59863bd552b96" + integrity sha512-xF88h0vFH8JkunSnmVrYfrR3LGTMAY+KTkHHF/S9BAOCsdaC83/hv4EmpcLxev7B+2yd3+xcitlsDFMBSo/gSw== dependencies: ansi-colors "^1.0.1" fancy-log "^1.3.2" @@ -4169,19 +3877,6 @@ gulp-tslint@^8.1.3: plugin-error "1.0.1" through "~2.3.8" -gulp-uglify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/gulp-uglify/-/gulp-uglify-3.0.0.tgz#0df0331d72a0d302e3e37e109485dddf33c6d1ca" - integrity sha1-DfAzHXKg0wLj434QlIXd3zPG0co= - dependencies: - gulplog "^1.0.0" - has-gulplog "^0.1.0" - lodash "^4.13.1" - make-error-cause "^1.1.1" - through2 "^2.0.0" - uglify-js "^3.0.5" - vinyl-sourcemaps-apply "^0.2.0" - gulp-untar@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/gulp-untar/-/gulp-untar-0.0.7.tgz#92067d79e0fa1e92d60562a100233a44a5aa08b4" @@ -4287,13 +3982,6 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= -has-gulplog@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" - integrity sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4= - dependencies: - sparkles "^1.0.0" - has-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" @@ -4385,11 +4073,6 @@ hawk@~6.0.2: hoek "4.x.x" sntp "2.x.x" -he@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -4472,29 +4155,6 @@ http-proxy-agent@2.1.0, http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" -http-proxy@^1.8.1: - version "1.17.0" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" - integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g== - dependencies: - eventemitter3 "^3.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - -http-server@^0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.11.1.tgz#2302a56a6ffef7f9abea0147d838a5e9b6b6a79b" - integrity sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w== - dependencies: - colors "1.0.3" - corser "~2.0.0" - ecstatic "^3.0.0" - http-proxy "^1.8.1" - opener "~1.4.0" - optimist "0.6.x" - portfinder "^1.0.13" - union "~0.4.3" - http-signature@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" @@ -4526,16 +4186,6 @@ https-proxy-agent@2.2.1, https-proxy-agent@^2.2.1: agent-base "^4.1.0" debug "^3.1.0" -husky@^0.13.1: - version "0.13.4" - resolved "https://registry.yarnpkg.com/husky/-/husky-0.13.4.tgz#48785c5028de3452a51c48c12c4f94b2124a1407" - integrity sha1-SHhcUCjeNFKlHEjBLE+UshJKFAc= - dependencies: - chalk "^1.1.3" - find-parent-dir "^0.3.0" - is-ci "^1.0.9" - normalize-path "^1.0.0" - iconv-lite@0.4.19, iconv-lite@^0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -4548,14 +4198,14 @@ iconv-lite@0.5.0: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.4.17, iconv-lite@^0.4.24: +iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.4.22, iconv-lite@^0.4.4: +iconv-lite@^0.4.4: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== @@ -4579,7 +4229,7 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" -ignore@^3.3.3, ignore@^3.3.5: +ignore@^3.3.5: version "3.3.10" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== @@ -4597,12 +4247,12 @@ import-fresh@^3.0.0: parent-module "^1.0.0" resolve-from "^4.0.0" -import-local@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" - integrity sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ== +import-local@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== dependencies: - pkg-dir "^2.0.0" + pkg-dir "^3.0.0" resolve-cwd "^2.0.0" imurmurhash@^0.1.4: @@ -4610,13 +4260,6 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= - dependencies: - repeating "^2.0.0" - indexes-of@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" @@ -4650,50 +4293,16 @@ ini@^1.3.4, ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" integrity sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4= +ini@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + innosetup@5.6.1: version "5.6.1" resolved "https://registry.yarnpkg.com/innosetup/-/innosetup-5.6.1.tgz#6e7031ba35b23e716e4f29686bc994052e0c278c" integrity sha512-Eit24N3JR8O0Wpuq/dMWCl2r550eiNP2124SbdbwOob43x89WPGL/SGpZG5EPHu20kV2N+4TwvHwFIM8pFUJ0g== -inquirer@^3.0.6: - version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" - integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.0.4" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - -inquirer@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.1.0.tgz#8f65c7b31c498285f4ddf3b742ad8c487892040b" - integrity sha512-f9K2MMx/G/AVmJSaZg2a+GVLRRmTdlGLbwxsibNd6yNTxXujqxPypjCnxnC0y4+Wb/rNY5KyKuq06AO5jrE+7w== - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^3.0.0" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.1.0" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - inquirer@^6.1.0: version "6.2.2" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.2.tgz#46941176f65c9eb20804627149b743a218f25406" @@ -4718,6 +4327,11 @@ int64-buffer@^0.1.9: resolved "https://registry.yarnpkg.com/int64-buffer/-/int64-buffer-0.1.9.tgz#9e039da043b24f78b196b283e04653ef5e990f61" integrity sha1-ngOdoEOyT3ixlrKD4EZT716ZD2E= +interpret@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" + integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== + interpret@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" @@ -4807,13 +4421,6 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" -is-ci@^1.0.9: - version "1.0.10" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e" - integrity sha1-9zkzayYyNlBhqdSCcM1WrjNpMY4= - dependencies: - ci-info "^1.0.0" - is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -4880,13 +4487,6 @@ is-extglob@^2.1.0, is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= -is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= - dependencies: - number-is-nan "^1.0.0" - is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" @@ -5025,11 +4625,6 @@ is-relative@^1.0.0: dependencies: is-unc-path "^1.0.0" -is-resolvable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== - is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -5220,11 +4815,6 @@ js-beautify@^1.8.9: mkdirp "~0.5.0" nopt "~4.0.1" -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= - js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -5246,7 +4836,7 @@ js-yaml@^3.12.0: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@^3.13.0, js-yaml@^3.9.1: +js-yaml@^3.13.0: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -5341,6 +4931,13 @@ json5@^0.5.0: resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" @@ -5527,6 +5124,15 @@ loader-runner@^2.3.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" integrity sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI= +loader-utils@1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== + dependencies: + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" + loader-utils@^1.0.2, loader-utils@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" @@ -5637,7 +5243,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.13.1, lodash@^4.15.0, lodash@^4.3.0: +lodash@^4.15.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" integrity sha1-eCA6TRwyiuHYbcpkYONptX9AVa4= @@ -5672,27 +5278,11 @@ long@^3.2.0: resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" integrity sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s= -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - lru-cache@2: version "2.7.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI= -lru-cache@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" - integrity sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - lru-cache@^4.1.1: version "4.1.2" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.2.tgz#45234b2e6e2f2b33da125624c4664929a0224c3f" @@ -5729,18 +5319,6 @@ make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" -make-error-cause@^1.1.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/make-error-cause/-/make-error-cause-1.2.2.tgz#df0388fcd0b37816dff0a5fb8108939777dcbc9d" - integrity sha1-3wOI/NCzeBbf8KX7gQiTl3fcvJ0= - dependencies: - make-error "^1.2.0" - -make-error@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.0.tgz#52ad3a339ccf10ce62b4040b708fe707244b8b96" - integrity sha1-Uq06M5zPEM5itAQLcI/nByRLi5Y= - make-iterator@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/make-iterator/-/make-iterator-1.0.1.tgz#29b33f312aa8f547c4a5e490f56afcec99133ad6" @@ -5765,12 +5343,7 @@ map-cache@^0.2.0, map-cache@^0.2.2: resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= -map-obj@^1.0.0, map-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= - -map-stream@~0.0.7: +map-stream@0.0.7, map-stream@~0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8" integrity sha1-ih8HiW2CsQkmvTdEokIACfiJdKg= @@ -5840,13 +5413,6 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= -mem@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= - dependencies: - mimic-fn "^1.0.0" - mem@^4.0.0: version "4.3.0" resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" @@ -5864,22 +5430,6 @@ memory-fs@^0.4.0, memory-fs@^0.4.1, memory-fs@~0.4.1: errno "^0.1.3" readable-stream "^2.0.1" -meow@^3.1.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" - merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -5991,16 +5541,11 @@ mime@1.4.1, mime@^1.3.4: resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== -mime@^1.4.1, mime@^1.6.0: +mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^2.0.3: - version "2.4.4" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" - integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== - mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" @@ -6046,7 +5591,7 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: +minimist@1.2.0, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= @@ -6100,14 +5645,7 @@ mkdirp@0.3.0: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" integrity sha1-G79asbqCevI1dRQ0kEJkVfSB/h4= -mkdirp@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" - integrity sha1-HXMHam35hs2TROFecfzAWkyavxI= - dependencies: - minimist "0.0.8" - -mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -6249,10 +5787,10 @@ native-keymap@2.0.0: resolved "https://registry.yarnpkg.com/native-keymap/-/native-keymap-2.0.0.tgz#7491ba8f9cc75bd6ada7e754dadb7716c793a3e3" integrity sha512-KIlDZp0yKaHaGIkEVdlYN3QIaZICXwG1qh/oeBeQdM8TwAi90IAZlAD57qsNDkEvIJIzerCzb5jYYQAdHGBgYg== -native-watchdog@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/native-watchdog/-/native-watchdog-1.0.0.tgz#97344e83cd6815a8c8e6c44a52e7be05832e65ca" - integrity sha512-HKQATz5KLUMPyQQ/QaalzgTXaGz2plYPBxjyalaR4ECIu/UznXY8YJD+a9SLkkcvtxnJ8/zHLY3xik06vUZ7uA== +native-watchdog@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/native-watchdog/-/native-watchdog-1.2.0.tgz#9c710093ac6e9e60b19517cb1ef4ac9d7c997395" + integrity sha512-jOOoA3PLSxt1adaeuEW7ymV9cApZiDxn4y4iFs7b4sP73EG+5Lsz+OgUNFcGMyrtznTw6ZvlLcilIN4jeAIgaQ== natural-compare@^1.4.0: version "1.4.0" @@ -6394,7 +5932,7 @@ nopt@~1.0.10: dependencies: abbrev "1" -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: +normalize-package-data@^2.3.2: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw== @@ -6404,11 +5942,6 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" - integrity sha1-MtDkcvkf80VwHBWoMRAY07CpA3k= - normalize-path@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" @@ -6495,19 +6028,6 @@ nth-check@~1.0.1: dependencies: boolbase "~1.0.0" -nugget@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/nugget/-/nugget-2.0.1.tgz#201095a487e1ad36081b3432fa3cada4f8d071b0" - integrity sha1-IBCVpIfhrTYIGzQy+jytpPjQcbA= - dependencies: - debug "^2.1.3" - minimist "^1.1.0" - pretty-bytes "^1.0.2" - progress-stream "^1.1.0" - request "^2.45.0" - single-line-log "^1.1.2" - throttleit "0.0.2" - num2fraction@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" @@ -6648,15 +6168,10 @@ oniguruma@^7.2.0: dependencies: nan "^2.14.0" -opener@~1.4.0: - version "1.4.3" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" - integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg= - -opn@^5.4.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" - integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== +opn@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-6.0.0.tgz#3c5b0db676d5f97da1233d1ed42d182bc5a27d2d" + integrity sha512-I9PKfIZC+e4RXZ/qr1RhgyCnGgYX0UEIlXgWnCOVACIvFgaC9rz6Won7xbdhoHrd8IIhV7YEpHjreNUNkqCGkQ== dependencies: is-wsl "^1.1.0" @@ -6667,7 +6182,7 @@ optimist@0.3.5: dependencies: wordwrap "~0.0.2" -optimist@0.6.x, optimist@^0.6.1: +optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= @@ -6719,15 +6234,6 @@ os-locale@^1.4.0: dependencies: lcid "^1.0.0" -os-locale@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== - dependencies: - execa "^0.7.0" - lcid "^1.0.0" - mem "^1.1.0" - os-locale@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" @@ -7007,7 +6513,7 @@ path-type@^3.0.0: dependencies: pify "^3.0.0" -pause-stream@0.0.11: +pause-stream@0.0.11, pause-stream@^0.0.11: version "0.0.11" resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= @@ -7074,6 +6580,13 @@ pkg-dir@^2.0.0: dependencies: find-up "^2.1.0" +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + plist@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.1.tgz#a9b931d17c304e8912ef0ba3bdd6182baf2e1f8c" @@ -7109,20 +6622,6 @@ plugin-error@1.0.1, plugin-error@^1.0.1: arr-union "^3.1.0" extend-shallow "^3.0.2" -pluralize@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" - integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== - -portfinder@^1.0.13: - version "1.0.20" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.20.tgz#bea68632e54b2e13ab7b0c4775e9b41bf270e44a" - integrity sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw== - dependencies: - async "^1.5.2" - debug "^2.2.0" - mkdirp "0.5.x" - posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -7414,14 +6913,6 @@ preserve@^0.2.0: resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= -pretty-bytes@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-1.0.4.tgz#0a22e8210609ad35542f8c8d5d2159aff0751c84" - integrity sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ= - dependencies: - get-stdin "^4.0.1" - meow "^3.1.0" - pretty-hrtime@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" @@ -7455,20 +6946,12 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= -progress-stream@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/progress-stream/-/progress-stream-1.2.0.tgz#2cd3cfea33ba3a89c9c121ec3347abe9ab125f77" - integrity sha1-LNPP6jO6OonJwSHsM0er6asSX3c= - dependencies: - speedometer "~0.1.2" - through2 "~0.2.3" - progress@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74= -progress@^2.0.0, progress@^2.0.1: +progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== @@ -7491,11 +6974,6 @@ proxy-addr@~2.0.2: forwarded "~0.1.2" ipaddr.js "1.5.2" -proxy-from-env@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" - integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4= - prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -7578,20 +7056,6 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -puppeteer@^1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.19.0.tgz#e3b7b448c2c97933517078d7a2c53687361bebea" - integrity sha512-2S6E6ygpoqcECaagDbBopoSOPDv0pAZvTbnBgUY+6hq0/XDFDOLEMNlHF/SKJlzcaZ9ckiKjKDuueWI3FN/WXw== - dependencies: - debug "^4.1.0" - extract-zip "^1.6.6" - https-proxy-agent "^2.2.1" - mime "^2.0.3" - progress "^2.0.1" - proxy-from-env "^1.0.0" - rimraf "^2.6.1" - ws "^6.1.0" - q@^1.0.1, q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -7602,11 +7066,6 @@ qs@6.5.1, qs@~6.5.1: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" integrity sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A== -qs@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404" - integrity sha1-6eha2+ddoLvkyOBHaghikPhjtAQ= - qs@~6.3.0: version "6.3.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" @@ -7694,16 +7153,6 @@ raw-body@2.3.2: iconv-lite "0.4.19" unpipe "1.0.0" -rc@^1.1.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.2.tgz#d8ce9cb57e8d64d9c7badd9876c7c34cbe3c7077" - integrity sha1-2M6ctX6NZNnHut2YdsfDTL48cHc= - dependencies: - deep-extend "~0.4.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -7780,7 +7229,7 @@ read@^1.0.7: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^1.1.8, readable-stream@~1.1.9: +readable-stream@^1.1.8: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= @@ -7850,14 +7299,6 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" -redent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - reduce-css-calc@^1.2.6: version "1.3.0" resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" @@ -7895,11 +7336,6 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexpp@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" - integrity sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw== - regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" @@ -7942,13 +7378,6 @@ repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= - dependencies: - is-finite "^1.0.0" - replace-ext@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" @@ -8003,7 +7432,7 @@ request@2.79.0: tunnel-agent "~0.4.1" uuid "^3.0.0" -"request@>= 2.44.0 < 3.0.0", request@^2.45.0, request@^2.79.0: +"request@>= 2.44.0 < 3.0.0", request@^2.79.0: version "2.83.0" resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" integrity sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw== @@ -8081,19 +7510,6 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -require-uncached@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM= - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= - resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -8109,11 +7525,6 @@ resolve-dir@^1.0.0, resolve-dir@^1.0.1: expand-tilde "^2.0.0" global-modules "^1.0.0" -resolve-from@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY= - resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" @@ -8211,18 +7622,6 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rx-lite-aggregates@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" - integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74= - dependencies: - rx-lite "*" - -rx-lite@*, rx-lite@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" - integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= - rxjs@5.4.0: version "5.4.0" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.4.0.tgz#a7db14ab157f9d7aac6a56e655e7a3860d39bf26" @@ -8230,13 +7629,6 @@ rxjs@5.4.0: dependencies: symbol-observable "^1.0.1" -rxjs@^6.1.0: - version "6.2.2" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.2.2.tgz#eb75fa3c186ff5289907d06483a77884586e1cf9" - integrity sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ== - dependencies: - tslib "^1.9.0" - rxjs@^6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504" @@ -8519,13 +7911,6 @@ simple-get@^2.7.0: once "^1.3.1" simple-concat "^1.0.0" -single-line-log@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/single-line-log/-/single-line-log-1.1.2.tgz#c2f83f273a3e1a16edb0995661da0ed5ef033364" - integrity sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q= - dependencies: - string-width "^1.0.1" - sinon@^1.17.2: version "1.17.7" resolved "https://registry.yarnpkg.com/sinon/-/sinon-1.17.7.tgz#4542a4f49ba0c45c05eb2e9dd9d203e2b8efe0bf" @@ -8541,13 +7926,6 @@ slash@^1.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= -slice-ansi@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" - integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== - dependencies: - is-fullwidth-code-point "^2.0.0" - slice-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" @@ -8705,11 +8083,6 @@ spdx-license-ids@^1.0.2: resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" integrity sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc= -speedometer@~0.1.2: - version "0.1.4" - resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d" - integrity sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0= - split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -8724,6 +8097,13 @@ split@0.3: dependencies: through "2" +split@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== + dependencies: + through "2" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -8790,6 +8170,14 @@ stream-browserify@^2.0.1: inherits "~2.0.1" readable-stream "^2.0.2" +stream-combiner@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.2.2.tgz#aec8cbac177b56b6f4fa479ced8c1912cee52858" + integrity sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg= + dependencies: + duplexer "~0.1.1" + through "~2.3.4" + stream-combiner@~0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" @@ -8852,7 +8240,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -8953,13 +8341,6 @@ strip-eof@^1.0.0: resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= - dependencies: - get-stdin "^4.0.1" - strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -8970,18 +8351,18 @@ sudo-prompt@9.0.0: resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.0.0.tgz#eebedeee9fcd6f661324e6bb46335e3288e8dc8a" integrity sha512-kUn5fiOk0nhY2oKD9onIkcNCE4Zt85WTsvOfSmqCplmlEvXCcPOmp1npH5YWuf8Bmyy9wLWkIxx+D+8cThBORQ== -sumchecker@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-2.0.2.tgz#0f42c10e5d05da5d42eea3e56c3399a37d6c5b3e" - integrity sha1-D0LBDl0F2l1C7qPlbDOZo31sWz4= - dependencies: - debug "^2.2.0" - supports-color@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" integrity sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4= +supports-color@6.1.0, supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" @@ -9008,20 +8389,13 @@ supports-color@^5.2.0: dependencies: has-flag "^3.0.0" -supports-color@^5.3.0, supports-color@^5.4.0: +supports-color@^5.3.0: version "5.4.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== dependencies: has-flag "^3.0.0" -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - sver-compat@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/sver-compat/-/sver-compat-1.5.0.tgz#3cf87dfeb4d07b4a3f14827bc186b3fd0c645cd8" @@ -9048,18 +8422,6 @@ symbol-observable@^1.0.1: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== -table@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" - integrity sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA== - dependencies: - ajv "^5.2.3" - ajv-keywords "^2.1.0" - chalk "^2.1.0" - lodash "^4.17.4" - slice-ansi "1.0.0" - string-width "^2.1.1" - table@^5.0.2: version "5.2.2" resolved "https://registry.yarnpkg.com/table/-/table-5.2.2.tgz#61d474c9e4d8f4f7062c98c7504acb3c08aa738f" @@ -9145,7 +8507,7 @@ temp@^0.8.3: os-tmpdir "^1.0.0" rimraf "~2.2.6" -text-table@^0.2.0, text-table@~0.2.0: +text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= @@ -9155,11 +8517,6 @@ textextensions@~1.0.0: resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-1.0.2.tgz#65486393ee1f2bb039a60cbba05b0b68bd9501d2" integrity sha1-ZUhjk+4fK7A5pgy7oFsLaL2VAdI= -throttleit@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf" - integrity sha1-z+34jmDADdlpe2H90qg0OptoDq8= - through2-filter@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec" @@ -9192,14 +8549,6 @@ through2@^3.0.0: readable-stream "2 || 3" xtend "~4.0.1" -through2@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-0.2.3.tgz#eb3284da4ea311b6cc8ace3653748a52abf25a3f" - integrity sha1-6zKE2k6jEbbMis42U3SKUqvyWj8= - dependencies: - readable-stream "~1.1.9" - xtend "~2.1.1" - through2@~0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/through2/-/through2-0.4.2.tgz#dbf5866031151ec8352bb6c4db64a2292a840b9b" @@ -9208,7 +8557,7 @@ through2@~0.4.0: readable-stream "~1.0.17" xtend "~2.1.1" -through@2, through@^2.3.6, through@^2.3.8, through@~2.3, through@~2.3.1, through@~2.3.8: +through@2, through@^2.3.6, through@^2.3.8, through@~2.3, through@~2.3.1, through@~2.3.4, through@~2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -9347,11 +8696,6 @@ tough-cookie@~2.4.3: resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk= -trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= - trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" @@ -9493,10 +8837,10 @@ typescript-formatter@7.1.0: commandpost "^1.0.0" editorconfig "^0.15.0" -typescript@3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.2.tgz#a09e1dc69bc9551cadf17dba10ee42cf55e5d56c" - integrity sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA== +typescript@3.6: + version "3.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.2.tgz#105b0f1934119dde543ac8eb71af3a91009efe54" + integrity sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw== typescript@^2.6.2: version "2.6.2" @@ -9508,14 +8852,6 @@ uc.micro@^1.0.1, uc.micro@^1.0.3: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" integrity sha1-ftUNXg+an7ClczeSWfKndFjVAZI= -uglify-es@^3.0.18: - version "3.1.9" - resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.1.9.tgz#6c82df628ac9eb7af9c61fd70c744a084abe6161" - integrity sha512-wVSiJKHDgDDFmxTVVvnbAH6IpamAFHYDI+5JvwPdaqIMnk8kRTX2JKwq1Fx7gb2+Jj5Dus8kzvIpKkWOMNU51w== - dependencies: - commander "~2.11.0" - source-map "~0.6.1" - uglify-es@^3.3.4: version "3.3.9" resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" @@ -9524,14 +8860,6 @@ uglify-es@^3.3.4: commander "~2.13.0" source-map "~0.6.1" -uglify-js@^3.0.5: - version "3.1.9" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.1.9.tgz#dffca799308cf327ec3ac77eeacb8e196ce3b452" - integrity sha512-ari2E89bD7f+fMU173NgF12JBcOhgoxeyuCs97h5K58IBENrnG9eVj2lFadrOPdqf0KifsxVmUQfzA2cHNxCZQ== - dependencies: - commander "~2.11.0" - source-map "~0.6.1" - uglify-js@^3.1.4: version "3.6.0" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5" @@ -9604,13 +8932,6 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^0.4.3" -union@~0.4.3: - version "0.4.6" - resolved "https://registry.yarnpkg.com/union/-/union-0.4.6.tgz#198fbdaeba254e788b0efcb630bc11f24a2959e0" - integrity sha1-GY+9rrolTniLDvy2MLwR8kopWeA= - dependencies: - qs "~2.3.3" - uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" @@ -9695,11 +9016,6 @@ url-join@^1.1.0: resolved "https://registry.yarnpkg.com/url-join/-/url-join-1.1.0.tgz#741c6c2f4596c4830d6718460920d0c92202dc78" integrity sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg= -url-join@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" - integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg= - url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -9747,10 +9063,10 @@ uuid@^3.0.1, uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== -v8-compile-cache@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c" - integrity sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw== +v8-compile-cache@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" + integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== v8-inspect-profiler@^0.0.20: version "0.0.20" @@ -9867,7 +9183,7 @@ vinyl-sourcemap@^1.1.0: remove-bom-buffer "^3.0.0" vinyl "^2.0.0" -vinyl-sourcemaps-apply@^0.2.0, vinyl-sourcemaps-apply@^0.2.1: +vinyl-sourcemaps-apply@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705" integrity sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU= @@ -9977,10 +9293,10 @@ vscode-chokidar@2.1.7: optionalDependencies: vscode-fsevents "1.2.12" -vscode-debugprotocol@1.36.0-pre.0: - version "1.36.0-pre.0" - resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.36.0-pre.0.tgz#4f998e143acae9e3ce13c308d4ad322f96841926" - integrity sha512-nQhImfsUJFfr73JqA2Uc1bjTvpgZRabqkkKQWUbmrrnTLCPKRCr9AgE44Ehb/vkLXNdo+vPnWjJXWnPGjT10mA== +vscode-debugprotocol@1.36.0: + version "1.36.0" + resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.36.0.tgz#88e6246045480a9cc643e819b597396eaa9d0f4b" + integrity sha512-F0MfcUkF88TfNf4iQbcmC+K9rA+zsrQpEz1XpTKidy5sMq8sYsJGUadYDGmmktfjRX+S/ebjHgM+YV/2qm6lVQ== vscode-fsevents@1.2.12: version "1.2.12" @@ -10022,10 +9338,10 @@ vscode-proxy-agent@0.4.0: https-proxy-agent "2.2.1" socks-proxy-agent "4.0.1" -vscode-ripgrep@^1.5.6: - version "1.5.6" - resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.6.tgz#93bf5c99ca5f8248950a305e224f6ca153c30af4" - integrity sha512-WRIM9XpUj6dsfdAmuI3ANbmT1ysPUVsYy/2uCLDHJa9kbiB4T7uGvFnnc0Rgx2qQnyRAwL7PeWaFgUljPPxf2g== +vscode-ripgrep@^1.5.7: + version "1.5.7" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.7.tgz#acb6b548af488a4bca5d0f1bb5faf761343289ce" + integrity sha512-/Vsz/+k8kTvui0q3O74pif9FK0nKopgFTiGNVvxicZANxtSA8J8gUE9GQ/4dpi7D/2yI/YVORszwVskFbz46hQ== vscode-sqlite3@4.0.8: version "4.0.8" @@ -10072,22 +9388,22 @@ watchpack@^1.5.0: graceful-fs "^4.1.2" neo-async "^2.5.0" -webpack-cli@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.1.0.tgz#d71a83687dcfeb758fdceeb0fe042f96bcf62994" - integrity sha512-p5NeKDtYwjZozUWq6kGNs9w+Gtw/CPvyuXjXn2HMdz8Tie+krjEg8oAtonvIyITZdvpF7XG9xDHwscLr2c+ugQ== +webpack-cli@^3.3.8: + version "3.3.8" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.8.tgz#caeaebcc26f685db1736e5decd3f01aac30123ec" + integrity sha512-RANYSXwikSWINjHMd/mtesblNSpjpDLoYTBtP99n1RhXqVI/wxN40Auqy42I7y4xrbmRBoA5Zy5E0JSBD5XRhw== dependencies: - chalk "^2.4.1" - cross-spawn "^6.0.5" - enhanced-resolve "^4.0.0" - global-modules-path "^2.1.0" - import-local "^1.0.0" - inquirer "^6.0.0" - interpret "^1.1.0" - loader-utils "^1.1.0" - supports-color "^5.4.0" - v8-compile-cache "^2.0.0" - yargs "^12.0.1" + chalk "2.4.2" + cross-spawn "6.0.5" + enhanced-resolve "4.1.0" + findup-sync "3.0.0" + global-modules "2.0.0" + import-local "2.0.0" + interpret "1.2.0" + loader-utils "1.2.3" + supports-color "6.1.0" + v8-compile-cache "2.0.3" + yargs "13.2.4" webpack-sources@^1.0.1, webpack-sources@^1.1.0: version "1.1.0" @@ -10168,7 +9484,7 @@ which-pm-runs@^1.0.0: resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= -which@^1.2.14: +which@^1.2.14, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -10264,13 +9580,6 @@ ws@^3.3.3: safe-buffer "~5.1.0" ultron "~1.1.0" -ws@^6.1.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" - integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== - dependencies: - async-limiter "~1.0.0" - xml-name-validator@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-1.0.0.tgz#dcf82ee092322951ef8cc1ba596c9cbfd14a83f1" @@ -10316,11 +9625,6 @@ xmldom@0.1.x: resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw= -xregexp@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020" - integrity sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg== - "xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" @@ -10333,27 +9637,27 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-search@0.2.0-beta5: - version "0.2.0-beta5" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta5.tgz#258d7cb1511d9060cd4520f0f82e408000fd4f53" - integrity sha512-Tg+d8scch0rYOVmzBbX35Y1GXtq+eu/YlzbXznmTo/yD83j3BQlXOhgECu/Yv8EX5JwFmzbfVRWC+JWnfigwGg== +xterm-addon-search@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0.tgz#46659c7c33f9fc268ad3e7e6c5824bb2fdb65852" + integrity sha512-C/v2VvFn3hb1qUgjJPo7LxzxNCLBgNJv8n6v/bH2NqPz32/PNUF+IHu0SFf1TaIH+pydUpKXCtob5a/UyZg/+Q== -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-addon-web-links@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.0.tgz#b408a0be46211d8d4a0bb5e701d8f3c2bd07d473" + integrity sha512-dq81c4Pzli2PgKVBgY2REte9sCVibR3df8AP3SEvCTM9uYFnUFxtxzMTplPnc7+rXabVhFdbU6x+rstIk8HNQg== -xterm@3.15.0-beta101: - version "3.15.0-beta101" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta101.tgz#38ffa0df5a3e9bdcb1818e74fe59b2f98b0fff69" - integrity sha512-HRa7+FDqQ8iWBTvb1Ni+uMGILnu6k9mF7JHMHRHfWxFoQlSoGYCyfdyXlJjk68YN8GsEQREmrII6cPLiQizdEQ== +xterm@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.0.0.tgz#eac93e08cbe69cf238cbace9185ed9e38873df1a" + integrity sha512-Xbx3vvf9FnrUcI1qU31Jww7/fc/NqpXGqgByTvjj7+g3/yPvt/RvLkP/LLMcof2kLAC3evzZGMiovs7NkjdWDw== y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= -"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: +y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== @@ -10368,13 +9672,6 @@ yallist@^3.0.0, yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" integrity sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k= -yargs-parser@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" - integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== - dependencies: - camelcase "^4.1.0" - yargs-parser@^13.1.0: version "13.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" @@ -10390,25 +9687,7 @@ yargs-parser@^5.0.0: dependencies: camelcase "^3.0.0" -yargs@^12.0.1: - version "12.0.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.1.tgz#6432e56123bb4e7c3562115401e98374060261c2" - integrity sha512-B0vRAp1hRX4jgIOWFtjfNjd9OA9RWYZ6tqGA9/I/IrTMsxmKvtWy+ersM+jzpQqbC3YfLzeABPdeTgcJ9eu1qQ== - dependencies: - cliui "^4.0.0" - decamelize "^2.0.0" - find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^10.1.0" - -yargs@^13.2.4: +yargs@13.2.4, yargs@^13.2.4: version "13.2.4" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" integrity sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg== @@ -10444,13 +9723,6 @@ yargs@^7.1.0: y18n "^3.2.1" yargs-parser "^5.0.0" -yauzl@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" - integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU= - dependencies: - fd-slicer "~1.0.1" - yauzl@^2.2.1, yauzl@^2.3.1: version "2.9.1" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f"