diff --git a/build/lib/optimize.js b/build/lib/optimize.js index bc2b5b12aea..e4783e18569 100644 --- a/build/lib/optimize.js +++ b/build/lib/optimize.js @@ -210,7 +210,12 @@ function minifyTask(src, sourceMapBaseUrl) { return cb => { const jsFilter = filter('**/*.js', { restore: true }); const cssFilter = filter('**/*.css', { restore: true }); - pump(gulp.src([src + '/**', '!' + src + '/**/*.map']), jsFilter, sourcemaps.init({ loadMaps: true }), uglifyWithCopyrights(), jsFilter.restore, cssFilter, minifyCSS({ reduceIdents: false }), cssFilter.restore, sourcemaps.write('./', { + pump(gulp.src([src + '/**', '!' + src + '/**/*.map']), jsFilter, sourcemaps.init({ loadMaps: true }), uglifyWithCopyrights(), jsFilter.restore, cssFilter, minifyCSS({ reduceIdents: false }), cssFilter.restore, sourcemaps.mapSources((sourcePath) => { + if (sourcePath === 'bootstrap-fork.js') { + return 'bootstrap-fork.orig.js'; + } + return sourcePath; + }), sourcemaps.write('./', { sourceMappingURL, sourceRoot: undefined, includeContent: true, diff --git a/build/lib/optimize.ts b/build/lib/optimize.ts index cb26dac7c2e..d15659ca6ea 100644 --- a/build/lib/optimize.ts +++ b/build/lib/optimize.ts @@ -298,6 +298,13 @@ export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) => cssFilter, minifyCSS({ reduceIdents: false }), cssFilter.restore, + (sourcemaps).mapSources((sourcePath: string) => { + if (sourcePath === 'bootstrap-fork.js') { + return 'bootstrap-fork.orig.js'; + } + + return sourcePath; + }), sourcemaps.write('./', { sourceMappingURL, sourceRoot: undefined, diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts index 6970507fee1..5875ea81fb0 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts @@ -178,8 +178,8 @@ suite('languages namespace tests', () => { await vscode.workspace.openTextDocument(uri); const result = await vscode.commands.executeCommand('vscode.executeCompletionItemProvider', uri, new vscode.Position(1, 0)); r1.dispose(); - assert.ok(ran); - assert.equal(result!.items[0].label, 'foo'); + assert.ok(ran, 'Provider has not been invoked'); + assert.ok(result!.items.some(i => i.label === 'foo'), 'Results do not include "foo"'); }); }); diff --git a/package.json b/package.json index 3b4e21265d5..98fc1ab153c 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "vscode-ripgrep": "^1.2.5", "vscode-sqlite3": "4.0.7", "vscode-textmate": "^4.0.1", - "vscode-xterm": "3.12.0-beta4", + "vscode-xterm": "3.12.0-beta5", "yauzl": "^2.9.1", "yazl": "^2.4.3" }, diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index ece0a772562..c4d5bc85314 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -8,17 +8,8 @@ "./typings", "./vs/base/**/*.ts", "./vs/code/**/*.ts", - "./vs/editor/browser/**/*.ts", - "./vs/editor/common/**/*.ts", - "./vs/editor/contrib/codeAction/**/*.ts", - "./vs/editor/contrib/format/**/*.ts", - "./vs/editor/contrib/gotoError/**/*.ts", - "./vs/editor/contrib/inPlaceReplace/**/*.ts", - "./vs/editor/contrib/smartSelect/**/*.ts", - "./vs/editor/contrib/snippet/**/*.ts", - "./vs/editor/contrib/suggest/**/*.ts", - "./vs/editor/contrib/documentSymbols/**/*.ts", - "./vs/editor/test/**/*.ts", + "./vs/editor/**/*.ts", + "./vs/platform/**/*.ts", "./vs/workbench/browser/parts/notifications/**/*", "./vs/workbench/browser/parts/quickinput/**/*", "./vs/workbench/electron-browser/actions/**/*", @@ -32,353 +23,9 @@ "./vs/workbench/services/themes/**/*.ts" ], "files": [ - "./vs/editor/contrib/bracketMatching/bracketMatching.ts", - "./vs/editor/contrib/bracketMatching/test/bracketMatching.test.ts", - "./vs/editor/contrib/caretOperations/caretOperations.ts", - "./vs/editor/contrib/caretOperations/moveCaretCommand.ts", - "./vs/editor/contrib/caretOperations/test/moveCarretCommand.test.ts", - "./vs/editor/contrib/caretOperations/transpose.ts", - "./vs/editor/contrib/clipboard/clipboard.ts", - "./vs/editor/contrib/codelens/codelens.ts", - "./vs/editor/contrib/codelens/codelensController.ts", - "./vs/editor/contrib/codelens/codelensWidget.ts", - "./vs/editor/contrib/colorPicker/color.ts", - "./vs/editor/contrib/colorPicker/colorDetector.ts", - "./vs/editor/contrib/colorPicker/colorPickerModel.ts", - "./vs/editor/contrib/colorPicker/colorPickerWidget.ts", - "./vs/editor/contrib/comment/blockCommentCommand.ts", - "./vs/editor/contrib/comment/comment.ts", - "./vs/editor/contrib/comment/lineCommentCommand.ts", - "./vs/editor/contrib/comment/test/blockCommentCommand.test.ts", - "./vs/editor/contrib/comment/test/lineCommentCommand.test.ts", - "./vs/editor/contrib/contextmenu/contextmenu.ts", - "./vs/editor/contrib/cursorUndo/cursorUndo.ts", - "./vs/editor/contrib/dnd/dnd.ts", - "./vs/editor/contrib/dnd/dragAndDropCommand.ts", - "./vs/editor/contrib/find/findController.ts", - "./vs/editor/contrib/find/findDecorations.ts", - "./vs/editor/contrib/find/findModel.ts", - "./vs/editor/contrib/find/findOptionsWidget.ts", - "./vs/editor/contrib/find/findState.ts", - "./vs/editor/contrib/find/findWidget.ts", - "./vs/editor/contrib/find/replaceAllCommand.ts", - "./vs/editor/contrib/find/replacePattern.ts", - "./vs/editor/contrib/find/simpleFindWidget.ts", - "./vs/editor/contrib/find/test/find.test.ts", - "./vs/editor/contrib/find/test/findController.test.ts", - "./vs/editor/contrib/find/test/findModel.test.ts", - "./vs/editor/contrib/find/test/replacePattern.test.ts", - "./vs/editor/contrib/folding/folding.ts", - "./vs/editor/contrib/folding/foldingDecorations.ts", - "./vs/editor/contrib/folding/foldingModel.ts", - "./vs/editor/contrib/folding/foldingRanges.ts", - "./vs/editor/contrib/folding/hiddenRangeModel.ts", - "./vs/editor/contrib/folding/indentRangeProvider.ts", - "./vs/editor/contrib/folding/intializingRangeProvider.ts", - "./vs/editor/contrib/folding/syntaxRangeProvider.ts", - "./vs/editor/contrib/folding/test/foldingModel.test.ts", - "./vs/editor/contrib/folding/test/foldingRanges.test.ts", - "./vs/editor/contrib/folding/test/hiddenRangeModel.test.ts", - "./vs/editor/contrib/folding/test/indentFold.test.ts", - "./vs/editor/contrib/folding/test/indentRangeProvider.test.ts", - "./vs/editor/contrib/folding/test/syntaxFold.test.ts", - "./vs/editor/contrib/fontZoom/fontZoom.ts", - "./vs/editor/contrib/goToDefinition/clickLinkGesture.ts", - "./vs/editor/contrib/goToDefinition/goToDefinition.ts", - "./vs/editor/contrib/hover/getHover.ts", - "./vs/editor/contrib/hover/hover.ts", - "./vs/editor/contrib/hover/hoverOperation.ts", - "./vs/editor/contrib/hover/hoverWidgets.ts", - "./vs/editor/contrib/hover/modesContentHover.ts", - "./vs/editor/contrib/hover/modesGlyphHover.ts", - "./vs/editor/contrib/indentation/indentUtils.ts", - "./vs/editor/contrib/indentation/indentation.ts", - "./vs/editor/contrib/indentation/test/indentation.test.ts", - "./vs/editor/contrib/linesOperations/copyLinesCommand.ts", - "./vs/editor/contrib/linesOperations/linesOperations.ts", - "./vs/editor/contrib/linesOperations/moveLinesCommand.ts", - "./vs/editor/contrib/linesOperations/sortLinesCommand.ts", - "./vs/editor/contrib/linesOperations/test/copyLinesCommand.test.ts", - "./vs/editor/contrib/linesOperations/test/linesOperations.test.ts", - "./vs/editor/contrib/linesOperations/test/moveLinesCommand.test.ts", - "./vs/editor/contrib/linesOperations/test/sortLinesCommand.test.ts", - "./vs/editor/contrib/links/getLinks.ts", - "./vs/editor/contrib/links/links.ts", - "./vs/editor/contrib/markdown/markdownRenderer.ts", - "./vs/editor/contrib/message/messageController.ts", - "./vs/editor/contrib/multicursor/multicursor.ts", - "./vs/editor/contrib/multicursor/test/multicursor.test.ts", - "./vs/editor/contrib/parameterHints/parameterHints.ts", - "./vs/editor/contrib/parameterHints/parameterHintsModel.ts", - "./vs/editor/contrib/parameterHints/parameterHintsWidget.ts", - "./vs/editor/contrib/parameterHints/provideSignatureHelp.ts", - "./vs/editor/contrib/parameterHints/test/parameterHintsModel.test.ts", - "./vs/editor/contrib/quickOpen/quickOpen.ts", - "./vs/editor/contrib/referenceSearch/peekViewWidget.ts", - "./vs/editor/contrib/referenceSearch/referencesModel.ts", - "./vs/editor/contrib/referenceSearch/referencesTree.ts", - "./vs/editor/contrib/referenceSearch/referencesWidget.ts", - "./vs/editor/contrib/referenceSearch/test/referencesModel.test.ts", - "./vs/editor/contrib/rename/rename.ts", - "./vs/editor/contrib/rename/renameInputField.ts", - "./vs/editor/contrib/suggest/test/suggestMemory.test.ts", - "./vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode.ts", - "./vs/editor/contrib/tokenization/tokenization.ts", - "./vs/editor/contrib/wordHighlighter/wordHighlighter.ts", - "./vs/editor/contrib/wordOperations/test/wordOperations.test.ts", - "./vs/editor/contrib/wordOperations/test/wordTestUtils.ts", - "./vs/editor/contrib/wordOperations/wordOperations.ts", - "./vs/editor/contrib/wordPartOperations/test/wordPartOperations.test.ts", - "./vs/editor/contrib/wordPartOperations/wordPartOperations.ts", - "./vs/editor/contrib/zoneWidget/zoneWidget.ts", - "./vs/editor/editor.api.ts", - "./vs/editor/editor.worker.ts", - "./vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts", - "./vs/editor/standalone/browser/colorizer.ts", - "./vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts", - "./vs/editor/standalone/browser/inspectTokens/inspectTokens.ts", - "./vs/editor/standalone/browser/quickOpen/editorQuickOpen.ts", - "./vs/editor/standalone/browser/quickOpen/gotoLine.ts", - "./vs/editor/standalone/browser/quickOpen/quickCommand.ts", - "./vs/editor/standalone/browser/quickOpen/quickOpenEditorWidget.ts", - "./vs/editor/standalone/browser/quickOpen/quickOutline.ts", - "./vs/editor/standalone/browser/simpleServices.ts", - "./vs/editor/standalone/browser/standaloneCodeEditor.ts", - "./vs/editor/standalone/browser/standaloneCodeServiceImpl.ts", - "./vs/editor/standalone/browser/standaloneEditor.ts", - "./vs/editor/standalone/browser/standaloneLanguages.ts", - "./vs/editor/standalone/browser/standaloneServices.ts", - "./vs/editor/standalone/browser/standaloneThemeServiceImpl.ts", - "./vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts", - "./vs/editor/standalone/common/monarch/monarchCommon.ts", - "./vs/editor/standalone/common/monarch/monarchCompile.ts", - "./vs/editor/standalone/common/monarch/monarchLexer.ts", - "./vs/editor/standalone/common/monarch/monarchTypes.ts", - "./vs/editor/standalone/common/standaloneThemeService.ts", - "./vs/editor/standalone/common/themes.ts", - "./vs/editor/standalone/test/browser/simpleServices.test.ts", - "./vs/editor/standalone/test/browser/standaloneLanguages.test.ts", - "./vs/editor/test/browser/controller/imeTester.ts", - "./vs/editor/test/browser/editorTestServices.ts", - "./vs/editor/test/browser/testCodeEditor.ts", - "./vs/editor/test/browser/testCommand.ts", - "./vs/editor/test/browser/view/minimapFontCreator.ts", - "./vs/editor/test/browser/view/viewLayer.test.ts", - "./vs/editor/test/common/commentMode.ts", - "./vs/editor/test/common/config/commonEditorConfig.test.ts", - "./vs/editor/test/common/controller/cursorMoveHelper.test.ts", - "./vs/editor/test/common/core/characterClassifier.test.ts", - "./vs/editor/test/common/core/lineTokens.test.ts", - "./vs/editor/test/common/core/range.test.ts", - "./vs/editor/test/common/core/viewLineToken.ts", - "./vs/editor/test/common/editorTestUtils.ts", - "./vs/editor/test/common/mocks/mockMode.ts", - "./vs/editor/test/common/mocks/testConfiguration.ts", - "./vs/editor/test/common/model/benchmark/benchmarkUtils.ts", - "./vs/editor/test/common/model/benchmark/entry.ts", - "./vs/editor/test/common/model/benchmark/modelbuilder.benchmark.ts", - "./vs/editor/test/common/model/benchmark/operations.benchmark.ts", - "./vs/editor/test/common/model/benchmark/searchNReplace.benchmark.ts", - "./vs/editor/test/common/model/editableTextModelAuto.test.ts", - "./vs/editor/test/common/model/editableTextModelTestUtils.ts", - "./vs/editor/test/common/model/linesTextBuffer/linesTextBufferBuilder.test.ts", - "./vs/editor/test/common/model/linesTextBuffer/textBufferAutoTestUtils.ts", - "./vs/editor/test/common/model/model.test.ts", - "./vs/editor/test/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.test.ts", - "./vs/editor/test/common/modes/languageConfiguration.test.ts", - "./vs/editor/test/common/modes/supports/characterPair.test.ts", - "./vs/editor/test/common/modes/supports/javascriptOnEnterRules.ts", - "./vs/editor/test/common/modes/supports/tokenization.test.ts", - "./vs/editor/test/common/modesTestUtils.ts", - "./vs/editor/test/common/services/languagesRegistry.test.ts", - "./vs/editor/test/common/view/minimapCharRendererFactory.ts", - "./vs/editor/test/common/view/overviewZoneManager.test.ts", - "./vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts", - "./vs/editor/test/common/viewLayout/lineDecorations.test.ts", - "./vs/editor/test/common/viewLayout/viewLineRenderer.test.ts", - "./vs/editor/test/common/viewLayout/whitespaceComputer.test.ts", - "./vs/editor/test/common/viewModel/characterHardWrappingLineMapper.test.ts", - "./vs/editor/test/common/viewModel/prefixSumComputer.test.ts", - "./vs/editor/test/common/viewModel/testViewModel.ts", - "./vs/editor/test/common/viewModel/viewModelDecorations.test.ts", - "./vs/editor/test/common/viewModel/viewModelImpl.test.ts", "./vs/monaco.d.ts", "./vs/nls.d.ts", "./vs/nls.mock.ts", - "./vs/platform/actions/browser/menuItemActionItem.ts", - "./vs/platform/actions/common/actions.ts", - "./vs/platform/actions/common/menuService.ts", - "./vs/platform/actions/test/common/menuService.test.ts", - "./vs/platform/backup/common/backup.ts", - "./vs/platform/backup/electron-main/backupMainService.ts", - "./vs/platform/browser/contextScopedHistoryWidget.ts", - "./vs/platform/clipboard/common/clipboardService.ts", - "./vs/platform/clipboard/electron-browser/clipboardService.ts", - "./vs/platform/commands/common/commands.ts", - "./vs/platform/commands/test/commands.test.ts", - "./vs/platform/configuration/common/configuration.ts", - "./vs/platform/configuration/common/configurationModels.ts", - "./vs/platform/configuration/common/configurationRegistry.ts", - "./vs/platform/configuration/node/configuration.ts", - "./vs/platform/configuration/node/configurationService.ts", - "./vs/platform/configuration/test/common/configuration.test.ts", - "./vs/platform/configuration/test/common/configurationModels.test.ts", - "./vs/platform/configuration/test/common/testConfigurationService.ts", - "./vs/platform/configuration/test/node/configurationService.test.ts", - "./vs/platform/contextkey/browser/contextKeyService.ts", - "./vs/platform/contextkey/common/contextkey.ts", - "./vs/platform/contextkey/common/contextkeys.ts", - "./vs/platform/contextkey/test/common/contextkey.test.ts", - "./vs/platform/contextview/browser/contextMenuHandler.ts", - "./vs/platform/contextview/browser/contextMenuService.ts", - "./vs/platform/contextview/browser/contextView.ts", - "./vs/platform/contextview/browser/contextViewService.ts", - "./vs/platform/diagnostics/electron-main/diagnosticsService.ts", - "./vs/platform/dialogs/common/dialogs.ts", - "./vs/platform/dialogs/node/dialogIpc.ts", - "./vs/platform/download/common/download.ts", - "./vs/platform/download/node/downloadIpc.ts", - "./vs/platform/download/node/downloadService.ts", - "./vs/platform/driver/electron-browser/driver.ts", - "./vs/platform/driver/electron-main/driver.ts", - "./vs/platform/driver/node/driver.ts", - "./vs/platform/editor/common/editor.ts", - "./vs/platform/environment/common/environment.ts", - "./vs/platform/environment/node/argv.ts", - "./vs/platform/environment/node/argvHelper.ts", - "./vs/platform/environment/node/environmentService.ts", - "./vs/platform/environment/test/node/environmentService.test.ts", - "./vs/platform/extensionManagement/common/extensionEnablementService.ts", - "./vs/platform/extensionManagement/common/extensionManagement.ts", - "./vs/platform/extensionManagement/common/extensionManagementUtil.ts", - "./vs/platform/extensionManagement/common/extensionNls.ts", - "./vs/platform/extensionManagement/node/extensionGalleryService.ts", - "./vs/platform/extensionManagement/node/extensionLifecycle.ts", - "./vs/platform/extensionManagement/node/extensionManagementIpc.ts", - "./vs/platform/extensionManagement/node/extensionManagementService.ts", - "./vs/platform/extensionManagement/node/extensionManagementUtil.ts", - "./vs/platform/extensionManagement/node/extensionsManifestCache.ts", - "./vs/platform/extensionManagement/test/electron-browser/extensionManagement.test.ts", - "./vs/platform/extensions/common/extensionHost.ts", - "./vs/platform/extensions/common/extensions.ts", - "./vs/platform/extensions/node/extensionValidator.ts", - "./vs/platform/extensions/node/extensionsUtil.ts", - "./vs/platform/extensions/test/node/extensionValidator.test.ts", - "./vs/platform/files/common/files.ts", - "./vs/platform/files/node/files.ts", - "./vs/platform/files/test/files.test.ts", - "./vs/platform/history/common/history.ts", - "./vs/platform/history/electron-main/historyMainService.ts", - "./vs/platform/history/electron-main/historyStorage.ts", - "./vs/platform/history/test/electron-main/historyStorage.test.ts", - "./vs/platform/instantiation/common/descriptors.ts", - "./vs/platform/instantiation/common/extensions.ts", - "./vs/platform/instantiation/common/graph.ts", - "./vs/platform/instantiation/common/instantiation.ts", - "./vs/platform/instantiation/common/instantiationService.ts", - "./vs/platform/instantiation/common/serviceCollection.ts", - "./vs/platform/instantiation/node/instantiationService.ts", - "./vs/platform/instantiation/test/common/graph.test.ts", - "./vs/platform/instantiation/test/common/instantiationService.test.ts", - "./vs/platform/instantiation/test/common/instantiationServiceMock.ts", - "./vs/platform/issue/common/issue.ts", - "./vs/platform/issue/electron-main/issueService.ts", - "./vs/platform/issue/node/issueIpc.ts", - "./vs/platform/jsonschemas/common/jsonContributionRegistry.ts", - "./vs/platform/keybinding/common/abstractKeybindingService.ts", - "./vs/platform/keybinding/common/keybinding.ts", - "./vs/platform/keybinding/common/keybindingResolver.ts", - "./vs/platform/keybinding/common/keybindingsRegistry.ts", - "./vs/platform/keybinding/common/resolvedKeybindingItem.ts", - "./vs/platform/keybinding/common/usLayoutResolvedKeybinding.ts", - "./vs/platform/keybinding/test/common/abstractKeybindingService.test.ts", - "./vs/platform/keybinding/test/common/keybindingLabels.test.ts", - "./vs/platform/keybinding/test/common/keybindingResolver.test.ts", - "./vs/platform/keybinding/test/common/mockKeybindingService.ts", - "./vs/platform/label/common/label.ts", - "./vs/platform/launch/electron-main/launchService.ts", - "./vs/platform/lifecycle/common/lifecycle.ts", - "./vs/platform/lifecycle/electron-browser/lifecycleService.ts", - "./vs/platform/lifecycle/electron-main/lifecycleMain.ts", - "./vs/platform/list/browser/listService.ts", - "./vs/platform/localizations/common/localizations.ts", - "./vs/platform/localizations/node/localizations.ts", - "./vs/platform/localizations/node/localizationsIpc.ts", - "./vs/platform/log/common/bufferLog.ts", - "./vs/platform/log/common/log.ts", - "./vs/platform/log/node/logIpc.ts", - "./vs/platform/log/node/spdlogService.ts", - "./vs/platform/markers/common/markerService.ts", - "./vs/platform/markers/common/markers.ts", - "./vs/platform/markers/test/common/markerService.test.ts", - "./vs/platform/menubar/common/menubar.ts", - "./vs/platform/menubar/electron-main/menubar.ts", - "./vs/platform/menubar/electron-main/menubarService.ts", - "./vs/platform/menubar/node/menubarIpc.ts", - "./vs/platform/node/package.ts", - "./vs/platform/node/product.ts", - "./vs/platform/notification/common/notification.ts", - "./vs/platform/notification/test/common/testNotificationService.ts", - "./vs/platform/opener/common/opener.ts", - "./vs/platform/progress/common/progress.ts", - "./vs/platform/quickOpen/common/quickOpen.ts", - "./vs/platform/quickinput/common/quickInput.ts", - "./vs/platform/registry/common/platform.ts", - "./vs/platform/registry/test/common/platform.test.ts", - "./vs/platform/remote/common/remoteAuthorityResolver.ts", - "./vs/platform/remote/common/remoteHosts.ts", - "./vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts", - "./vs/platform/remote/node/remoteAgentConnection.ts", - "./vs/platform/remote/node/remoteAgentFileSystemChannel.ts", - "./vs/platform/request/electron-browser/requestService.ts", - "./vs/platform/request/electron-main/requestService.ts", - "./vs/platform/request/node/request.ts", - "./vs/platform/request/node/requestService.ts", - "./vs/platform/state/common/state.ts", - "./vs/platform/state/node/stateService.ts", - "./vs/platform/statusbar/common/statusbar.ts", - "./vs/platform/storage/common/storage.ts", - "./vs/platform/storage/node/storageIpc.ts", - "./vs/platform/storage/node/storageMainService.ts", - "./vs/platform/storage/node/storageService.ts", - "./vs/platform/telemetry/browser/errorTelemetry.ts", - "./vs/platform/telemetry/common/telemetry.ts", - "./vs/platform/telemetry/common/telemetryService.ts", - "./vs/platform/telemetry/common/telemetryUtils.ts", - "./vs/platform/telemetry/node/appInsightsAppender.ts", - "./vs/platform/telemetry/node/commonProperties.ts", - "./vs/platform/telemetry/node/telemetryIpc.ts", - "./vs/platform/telemetry/node/telemetryNodeUtils.ts", - "./vs/platform/telemetry/node/workbenchCommonProperties.ts", - "./vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts", - "./vs/platform/telemetry/test/electron-browser/telemetryService.test.ts", - "./vs/platform/theme/common/colorRegistry.ts", - "./vs/platform/theme/common/styler.ts", - "./vs/platform/theme/common/themeService.ts", - "./vs/platform/theme/test/common/testThemeService.ts", - "./vs/platform/update/common/update.ts", - "./vs/platform/update/electron-main/abstractUpdateService.ts", - "./vs/platform/update/electron-main/updateService.darwin.ts", - "./vs/platform/update/electron-main/updateService.linux.ts", - "./vs/platform/update/electron-main/updateService.snap.ts", - "./vs/platform/update/electron-main/updateService.win32.ts", - "./vs/platform/update/node/update.config.contribution.ts", - "./vs/platform/update/node/updateIpc.ts", - "./vs/platform/url/common/url.ts", - "./vs/platform/url/common/urlService.ts", - "./vs/platform/url/electron-main/electronUrlListener.ts", - "./vs/platform/url/node/urlIpc.ts", - "./vs/platform/windows/common/windows.ts", - "./vs/platform/windows/electron-browser/windowService.ts", - "./vs/platform/windows/electron-main/windows.ts", - "./vs/platform/windows/electron-main/windowsService.ts", - "./vs/platform/windows/node/windowsIpc.ts", - "./vs/platform/workspace/common/workspace.ts", - "./vs/platform/workspace/test/common/testWorkspace.ts", - "./vs/platform/workspace/test/common/workspace.test.ts", - "./vs/platform/workspaces/common/workspaces.ts", - "./vs/platform/workspaces/electron-main/workspacesMainService.ts", - "./vs/platform/workspaces/node/workspacesIpc.ts", "./vs/vscode.d.ts", "./vs/vscode.proposed.d.ts", "./vs/workbench/api/common/configurationExtensionPoint.ts", @@ -416,7 +63,7 @@ "./vs/workbench/api/electron-browser/mainThreadWorkspace.ts", "./vs/workbench/api/node/extHost.protocol.ts", "./vs/workbench/api/node/extHostClipboard.ts", - "vs/workbench/api/node/extHostConfiguration.ts", + "./vs/workbench/api/node/extHostConfiguration.ts", "./vs/workbench/api/node/extHostDecorations.ts", "./vs/workbench/api/node/extHostDialogs.ts", "./vs/workbench/api/node/extHostDocumentData.ts", @@ -673,8 +320,8 @@ "./vs/workbench/services/configuration/common/configuration.ts", "./vs/workbench/services/configuration/common/configurationModels.ts", "./vs/workbench/services/configuration/common/jsonEditing.ts", + "./vs/workbench/services/configuration/node/configuration.ts", "./vs/workbench/services/configuration/node/jsonEditingService.ts", - "vs/workbench/services/configuration/node/configuration.ts", "./vs/workbench/services/configuration/test/common/configurationModels.test.ts", "./vs/workbench/services/configurationResolver/common/configurationResolver.ts", "./vs/workbench/services/configurationResolver/common/configurationResolverSchema.ts", @@ -774,7 +421,7 @@ "./vs/workbench/test/common/editor/editorOptions.test.ts", "./vs/workbench/test/common/notifications.test.ts", "./vs/workbench/test/electron-browser/api/extHost.api.impl.test.ts", - "vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts", + "./vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts", "./vs/workbench/test/electron-browser/api/extHostDocumentData.test.ts", "./vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts", "./vs/workbench/test/electron-browser/api/extHostTypes.test.ts", diff --git a/src/vs/base/browser/ui/findinput/findInput.ts b/src/vs/base/browser/ui/findinput/findInput.ts index 070c88e284d..59275522535 100644 --- a/src/vs/base/browser/ui/findinput/findInput.ts +++ b/src/vs/base/browser/ui/findinput/findInput.ts @@ -42,7 +42,6 @@ export class FindInput extends Widget { static readonly OPTION_CHANGE: string = 'optionChange'; private contextViewProvider: IContextViewProvider; - private width: number; private placeholder: string; private validation?: IInputValidator; private label: string; @@ -93,7 +92,6 @@ export class FindInput extends Widget { constructor(parent: HTMLElement | null, contextViewProvider: IContextViewProvider, private readonly _showOptionButtons: boolean, options: IFindInputOptions) { super(); this.contextViewProvider = contextViewProvider; - this.width = options.width || 100; this.placeholder = options.placeholder || ''; this.validation = options.validation; this.label = options.label || NLS_DEFAULT_LABEL; @@ -159,13 +157,6 @@ export class FindInput extends Widget { this.focus(); } - public setWidth(newWidth: number): void { - this.width = newWidth; - this.domNode.style.width = this.width + 'px'; - this.contextViewProvider.layout(); - this.setInputWidth(); - } - public getValue(): string { return this.inputBox.value; } @@ -240,7 +231,6 @@ export class FindInput extends Widget { public setCaseSensitive(value: boolean): void { this.caseSensitive.checked = value; - this.setInputWidth(); } public getWholeWords(): boolean { @@ -249,7 +239,6 @@ export class FindInput extends Widget { public setWholeWords(value: boolean): void { this.wholeWords.checked = value; - this.setInputWidth(); } public getRegex(): boolean { @@ -258,7 +247,6 @@ export class FindInput extends Widget { public setRegex(value: boolean): void { this.regex.checked = value; - this.setInputWidth(); this.validate(); } @@ -277,15 +265,8 @@ export class FindInput extends Widget { dom.addClass(this.domNode, 'highlight-' + (this._lastHighlightFindOptions)); } - private setInputWidth(): void { - let w = this.width - this.caseSensitive.width() - this.wholeWords.width() - this.regex.width(); - this.inputBox.width = w; - this.inputBox.layout(); - } - private buildDomNode(appendCaseSensitiveLabel: string, appendWholeWordsLabel: string, appendRegexLabel: string, history: string[], flexibleHeight: boolean): void { this.domNode = document.createElement('div'); - this.domNode.style.width = this.width + 'px'; dom.addClass(this.domNode, 'monaco-findInput'); this.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, { @@ -320,7 +301,6 @@ export class FindInput extends Widget { if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) { this.inputBox.focus(); } - this.setInputWidth(); this.validate(); })); this._register(this.regex.onKeyDown(e => { @@ -337,7 +317,6 @@ export class FindInput extends Widget { if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) { this.inputBox.focus(); } - this.setInputWidth(); this.validate(); })); @@ -351,7 +330,6 @@ export class FindInput extends Widget { if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) { this.inputBox.focus(); } - this.setInputWidth(); this.validate(); })); this._register(this.caseSensitive.onKeyDown(e => { @@ -390,7 +368,6 @@ export class FindInput extends Widget { } }); - this.setInputWidth(); let controls = document.createElement('div'); controls.className = 'controls'; diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index 1acd51e015f..c35537fa7ea 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -194,6 +194,10 @@ export class PagedList implements IDisposable { this.list.layout(height, width); } + toggleKeyboardNavigation(): void { + this.list.toggleKeyboardNavigation(); + } + reveal(index: number, relativeTop?: number): void { this.list.reveal(index, relativeTop); } diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index a342692f5c8..69ccfbbdb3c 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -334,6 +334,10 @@ class TypeLabelController implements IDisposable { private enabled = false; private state: TypeLabelControllerState = TypeLabelControllerState.Idle; + + private automaticKeyboardNavigation = true; + private triggered = false; + private enabledDisposables: IDisposable[] = []; private disposables: IDisposable[] = []; @@ -342,11 +346,10 @@ class TypeLabelController implements IDisposable { private view: ListView, private keyboardNavigationLabelProvider: IKeyboardNavigationLabelProvider ) { - list.onDidUpdateOptions(this.onDidUpdateListOptions, this, this.disposables); - this.onDidUpdateListOptions(list.options); + this.updateOptions(list.options); } - private onDidUpdateListOptions(options: IListOptions): void { + updateOptions(options: IListOptions): void { const enableKeyboardNavigation = typeof options.enableKeyboardNavigation === 'undefined' ? true : !!options.enableKeyboardNavigation; if (enableKeyboardNavigation) { @@ -354,6 +357,14 @@ class TypeLabelController implements IDisposable { } else { this.disable(); } + + if (typeof options.automaticKeyboardNavigation !== 'undefined') { + this.automaticKeyboardNavigation = options.automaticKeyboardNavigation; + } + } + + toggle(): void { + this.triggered = !this.triggered; } private enable(): void { @@ -363,6 +374,7 @@ class TypeLabelController implements IDisposable { const onChar = Event.chain(domEvent(this.view.domNode, 'keydown')) .filter(e => !isInputElement(e.target as HTMLElement)) + .filter(() => this.automaticKeyboardNavigation || this.triggered) .map(event => new StandardKeyboardEvent(event)) .filter(this.keyboardNavigationLabelProvider.mightProducePrintableCharacter ? e => this.keyboardNavigationLabelProvider.mightProducePrintableCharacter!(e) : e => mightProducePrintableCharacter(e)) .forEach(e => { e.stopPropagation(); e.preventDefault(); }) @@ -375,6 +387,7 @@ class TypeLabelController implements IDisposable { onInput(this.onInput, this, this.enabledDisposables); this.enabled = true; + this.triggered = false; } private disable(): void { @@ -384,11 +397,13 @@ class TypeLabelController implements IDisposable { this.enabledDisposables = dispose(this.enabledDisposables); this.enabled = false; + this.triggered = false; } private onInput(word: string | null): void { if (!word) { this.state = TypeLabelControllerState.Idle; + this.triggered = false; return; } @@ -797,6 +812,7 @@ export interface IListOptions extends IListStyles { readonly identityProvider?: IIdentityProvider; readonly dnd?: IListDragAndDrop; readonly enableKeyboardNavigation?: boolean; + readonly automaticKeyboardNavigation?: boolean; readonly keyboardNavigationLabelProvider?: IKeyboardNavigationLabelProvider; readonly ariaRole?: ListAriaRootRole; readonly ariaLabel?: string; @@ -1061,6 +1077,7 @@ class ListViewDragAndDrop implements IListViewDragAndDrop { export interface IListOptionsUpdate { readonly enableKeyboardNavigation?: boolean; + readonly automaticKeyboardNavigation?: boolean; } export class List implements ISpliceable, IDisposable { @@ -1072,9 +1089,7 @@ export class List implements ISpliceable, IDisposable { private spliceable: ISpliceable; private styleElement: HTMLStyleElement; private styleController: IStyleController; - - private _onDidUpdateOptions = new Emitter>(); - readonly onDidUpdateOptions = this._onDidUpdateOptions.event; + private typeLabelController?: TypeLabelController; protected disposables: IDisposable[]; @@ -1209,8 +1224,8 @@ export class List implements ISpliceable, IDisposable { } if (_options.keyboardNavigationLabelProvider) { - const controller = new TypeLabelController(this, this.view, _options.keyboardNavigationLabelProvider); - this.disposables.push(controller); + this.typeLabelController = new TypeLabelController(this, this.view, _options.keyboardNavigationLabelProvider); + this.disposables.push(this.typeLabelController); } this.disposables.push(this.createMouseController(_options)); @@ -1231,7 +1246,10 @@ export class List implements ISpliceable, IDisposable { updateOptions(optionsUpdate: IListOptionsUpdate = {}): void { this._options = { ...this._options, ...optionsUpdate }; - this._onDidUpdateOptions.fire(this._options); + + if (this.typeLabelController) { + this.typeLabelController.updateOptions(this._options); + } } get options(): IListOptions { @@ -1298,6 +1316,12 @@ export class List implements ISpliceable, IDisposable { this.view.layout(height, width); } + toggleKeyboardNavigation(): void { + if (this.typeLabelController) { + this.typeLabelController.toggle(); + } + } + setSelection(indexes: number[], browserEvent?: UIEvent): void { for (const index of indexes) { if (index < 0 || index >= this.length) { diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index ab9e2eba27b..fa30edc24f8 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -405,7 +405,7 @@ class TypeFilterController implements IDisposable { private clearDomNode: HTMLElement; private keyboardNavigationEventFilter?: IKeyboardNavigationEventFilter; - private automaticKeyboardNavigation: boolean; + private automaticKeyboardNavigation = true; private triggered = false; private enabledDisposables: IDisposable[] = []; @@ -457,7 +457,10 @@ class TypeFilterController implements IDisposable { this.filterOnTypeDomNode.checked = this._filterOnType; } - this.automaticKeyboardNavigation = typeof options.automaticKeyboardNavigation === 'undefined' ? true : options.automaticKeyboardNavigation; + if (typeof options.automaticKeyboardNavigation !== 'undefined') { + this.automaticKeyboardNavigation = options.automaticKeyboardNavigation; + } + this.tree.refilter(); this.render(); @@ -485,7 +488,7 @@ class TypeFilterController implements IDisposable { .filter(this.keyboardNavigationEventFilter || (() => true)) .filter(() => this.automaticKeyboardNavigation || this.triggered) .map(e => new StandardKeyboardEvent(e)) - .filter(e => isPrintableCharEvent(e) || ((this._pattern.length > 0 || this.triggered) && ((e.keyCode === KeyCode.Escape || e.keyCode === KeyCode.Backspace) && !e.altKey && !e.ctrlKey && !e.metaKey) || (e.keyCode === KeyCode.Backspace && (isMacintosh ? e.altKey : e.ctrlKey)))) + .filter(e => isPrintableCharEvent(e) || ((this._pattern.length > 0 || this.triggered) && ((e.keyCode === KeyCode.Escape || e.keyCode === KeyCode.Backspace) && !e.altKey && !e.ctrlKey && !e.metaKey) || (e.keyCode === KeyCode.Backspace && (isMacintosh ? e.altKey : e.ctrlKey) && !e.shiftKey))) .forEach(e => { e.stopPropagation(); e.preventDefault(); }) .event; @@ -970,6 +973,9 @@ export abstract class AbstractTree implements IDisposable get openOnSingleClick(): boolean { return typeof this._options.openOnSingleClick === 'undefined' ? true : this._options.openOnSingleClick; } get expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) { return typeof this._options.expandOnlyOnTwistieClick === 'undefined' ? false : this._options.expandOnlyOnTwistieClick; } + private _onDidUpdateOptions = new Emitter>(); + readonly onDidUpdateOptions: Event> = this._onDidUpdateOptions.event; + get onDidDispose(): Event { return this.view.onDidDispose; } constructor( @@ -1028,11 +1034,16 @@ export abstract class AbstractTree implements IDisposable renderer.updateOptions(optionsUpdate); } - this.view.updateOptions({ enableKeyboardNavigation: this._options.simpleKeyboardNavigation }); + this.view.updateOptions({ + enableKeyboardNavigation: this._options.simpleKeyboardNavigation, + automaticKeyboardNavigation: this._options.automaticKeyboardNavigation + }); if (this.typeFilterController) { this.typeFilterController.updateOptions(this._options); } + + this._onDidUpdateOptions.fire(this._options); } get options(): IAbstractTreeOptions { @@ -1140,11 +1151,11 @@ export abstract class AbstractTree implements IDisposable } toggleKeyboardNavigation(): void { - if (!this.typeFilterController) { - return; - } + this.view.toggleKeyboardNavigation(); - this.typeFilterController.toggle(); + if (this.typeFilterController) { + this.typeFilterController.toggle(); + } } refilter(): void { @@ -1231,10 +1242,6 @@ export abstract class AbstractTree implements IDisposable // List - get visibleNodeCount(): number { - return this.view.length; - } - private onLeftArrow(e: StandardKeyboardEvent): void { e.preventDefault(); e.stopPropagation(); diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 79db4cd6c79..54fabcf7def 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -9,7 +9,7 @@ import { IListVirtualDelegate, IIdentityProvider, IListDragAndDrop, IListDragOve import { ITreeElement, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeSorter, ICollapseStateChangeEvent, IAsyncDataSource, ITreeDragAndDrop } 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, always, CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; +import { timeout, CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; import { IListStyles } from 'vs/base/browser/ui/list/listWidget'; import { Iterator } from 'vs/base/common/iterator'; import { IDragAndDropData } from 'vs/base/browser/dnd'; @@ -571,12 +571,6 @@ export class AsyncDataTree implements IDisposable return (node && node.element)!; } - // List - - get visibleNodeCount(): number { - return this.tree.visibleNodeCount; - } - // Implementation private getDataNode(element: TInput | T): IAsyncDataTreeNode { @@ -679,7 +673,8 @@ export class AsyncDataTree implements IDisposable this._onDidChangeNodeSlowState.fire(node); }, _ => null); - childrenPromise = always(this.doGetChildren(node), () => slowTimeout.cancel()); + childrenPromise = this.doGetChildren(node) + .finally(() => slowTimeout.cancel()); } try { @@ -721,8 +716,10 @@ export class AsyncDataTree implements IDisposable return children; }); + this.refreshPromises.set(node, result); - return always(result, () => this.refreshPromises.delete(node)); + + return result.finally(() => this.refreshPromises.delete(node)); } private _onDidChangeCollapseState({ node, deep }: ICollapseStateChangeEvent, any>): void { diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index 79c7a1c8071..080a2c7a273 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -45,7 +45,7 @@ export function createCancelablePromise(callback: (token: CancellationToken) return this.then(undefined, reject); } finally(onfinally?: (() => void) | undefined | null): Promise { - return always(promise, onfinally || (() => { })); + return promise.finally(onfinally); } }; } @@ -326,25 +326,6 @@ export function disposableTimeout(handler: () => void, timeout = 0): IDisposable return toDisposable(() => clearTimeout(timer)); } -/** - * Returns a new promise that joins the provided promise. Upon completion of - * the provided promise the provided function will always be called. This - * method is comparable to a try-finally code block. - * @param promise a promise - * @param callback a function that will be call in the success and error case. - */ -export function always(promise: Promise, callback: () => void): Promise { - function safeCallback() { - try { - callback(); - } catch (err) { - errors.onUnexpectedError(err); - } - } - promise.then(_ => safeCallback(), _ => safeCallback()); - return Promise.resolve(promise); -} - export function ignoreErrors(promise: Promise): Promise { return promise.then(undefined, _ => undefined); } diff --git a/src/vs/base/common/cache.ts b/src/vs/base/common/cache.ts index 42c07e4d289..f46d663f773 100644 --- a/src/vs/base/common/cache.ts +++ b/src/vs/base/common/cache.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; -import { always } from 'vs/base/common/async'; export interface CacheResult { promise: Promise; @@ -23,7 +22,7 @@ export class Cache { const cts = new CancellationTokenSource(); const promise = this.task(cts.token); - always(promise, () => cts.dispose()); + promise.finally(() => cts.dispose()); this.result = { promise, diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 4438fa3db74..29eafda5275 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -102,6 +102,25 @@ export namespace Event { }); } + /** + * Given a chain of event processing functions (filter, map, etc), each + * function will be invoked per event & per listener. Snapshotting an event + * chain allows each function to be invoked just once per event. + */ + export function snapshot(event: Event): Event { + let listener: IDisposable; + const emitter = new Emitter({ + onFirstListenerAdd: () => { + listener = event(emitter.fire, emitter); + }, + onLastListenerRemove: () => { + listener.dispose(); + } + }); + + return emitter.event; + } + /** * Debounces the provided event, given a `merge` function. * @@ -286,7 +305,9 @@ export namespace Event { class ChainableEvent implements IChainableEvent { - get event(): Event { return this._event; } + get event(): Event { + return snapshot(this._event); + } constructor(private _event: Event) { } diff --git a/src/vs/base/common/extpath.ts b/src/vs/base/common/extpath.ts index a829cbcf5fe..5589e35aeb4 100644 --- a/src/vs/base/common/extpath.ts +++ b/src/vs/base/common/extpath.ts @@ -263,6 +263,10 @@ export function isValidBasename(name: string | null | undefined): boolean { return false; // Windows: file cannot end with a whitespace } + if (name.length > 255) { + return false; // most file systems do not allow files > 255 lenth + } + return true; } diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts index 864c6bdc620..85168b0d0e4 100644 --- a/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts @@ -3,13 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +export const LANGUAGE_DEFAULT = 'en'; + let _isWindows = false; let _isMacintosh = false; let _isLinux = false; let _isNative = false; let _isWeb = false; let _locale: string | undefined = undefined; -let _language: string | undefined = undefined; +let _language: string = LANGUAGE_DEFAULT; let _translationsConfigFile: string | undefined = undefined; interface NLSConfig { @@ -42,8 +44,6 @@ interface INavigator { declare let navigator: INavigator; declare let self: any; -export const LANGUAGE_DEFAULT = 'en'; - const isElectronRenderer = (typeof process !== 'undefined' && typeof process.versions !== 'undefined' && typeof process.versions.electron !== 'undefined' && process.type === 'renderer'); // OS detection diff --git a/src/vs/base/parts/ipc/node/ipc.cp.ts b/src/vs/base/parts/ipc/node/ipc.cp.ts index 2217c707d22..3125c3d7156 100644 --- a/src/vs/base/parts/ipc/node/ipc.cp.ts +++ b/src/vs/base/parts/ipc/node/ipc.cp.ts @@ -5,7 +5,7 @@ import { ChildProcess, fork, ForkOptions } from 'child_process'; import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle'; -import { Delayer, always, createCancelablePromise } from 'vs/base/common/async'; +import { Delayer, createCancelablePromise } from 'vs/base/common/async'; import { deepClone, assign } from 'vs/base/common/objects'; import { Emitter, Event } from 'vs/base/common/event'; import { createQueuedSender } from 'vs/base/node/processes'; @@ -132,7 +132,7 @@ export class Client implements IChannelClient, IDisposable { const disposable = toDisposable(() => result.cancel()); this.activeRequests.add(disposable); - always(result, () => { + result.finally(() => { cancellationTokenListener.dispose(); this.activeRequests.delete(disposable); diff --git a/src/vs/base/parts/ipc/node/ipc.ts b/src/vs/base/parts/ipc/node/ipc.ts index e0e7b9ad3ac..07a952cb54d 100644 --- a/src/vs/base/parts/ipc/node/ipc.ts +++ b/src/vs/base/parts/ipc/node/ipc.ts @@ -5,7 +5,7 @@ import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { Event, Emitter, Relay } from 'vs/base/common/event'; -import { always, CancelablePromise, createCancelablePromise, timeout } from 'vs/base/common/async'; +import { CancelablePromise, createCancelablePromise, timeout } from 'vs/base/common/async'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import * as errors from 'vs/base/common/errors'; @@ -448,9 +448,7 @@ export class ChannelClient implements IChannelClient, IDisposable { this.activeRequests.add(disposable); }); - always(result, () => this.activeRequests.delete(disposable)); - - return result; + return result.finally(() => this.activeRequests.delete(disposable)); } private requestEvent(channelName: string, name: string, arg?: any): Event { diff --git a/src/vs/base/parts/ipc/test/node/ipc.cp.test.ts b/src/vs/base/parts/ipc/test/node/ipc.cp.test.ts index 2c3ef666c01..147a2be5131 100644 --- a/src/vs/base/parts/ipc/test/node/ipc.cp.test.ts +++ b/src/vs/base/parts/ipc/test/node/ipc.cp.test.ts @@ -5,7 +5,6 @@ import * as assert from 'assert'; import { Client } from 'vs/base/parts/ipc/node/ipc.cp'; -import { always } from 'vs/base/common/async'; import { TestServiceClient } from './testService'; import { getPathFromAmdModule } from 'vs/base/common/amd'; @@ -27,7 +26,7 @@ suite('IPC, Child Process', () => { assert.equal(r.outgoing, 'pong'); }); - return always(result, () => client.dispose()); + return result.finally(() => client.dispose()); }); test('events', () => { @@ -49,7 +48,7 @@ suite('IPC, Child Process', () => { const request = service.marco(); const result = Promise.all([request, event]); - return always(result, () => client.dispose()); + return result.finally(() => client.dispose()); }); test('event dispose', () => { @@ -74,6 +73,6 @@ suite('IPC, Child Process', () => { assert.equal(count, 2); }); - return always(result, () => client.dispose()); + return result.finally(() => client.dispose()); }); }); diff --git a/src/vs/base/test/common/event.test.ts b/src/vs/base/test/common/event.test.ts index a08f0aa538c..2682f307b22 100644 --- a/src/vs/base/test/common/event.test.ts +++ b/src/vs/base/test/common/event.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { Event, Emitter, EventBufferer, EventMultiplexer, AsyncEmitter, IWaitUntil } from 'vs/base/common/event'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import * as Errors from 'vs/base/common/errors'; import { timeout } from 'vs/base/common/async'; @@ -777,4 +777,37 @@ suite('Event utils', () => { listener.dispose(); }); + + test('snapshot', () => { + const disposables: IDisposable[] = []; + + const emitter = new Emitter(); + let count = 0; + const event = Event.forEach(emitter.event, () => count++); + + // one listener + event(() => null, null, disposables); + emitter.fire(); + assert.equal(count, 1); + dispose(disposables); + + // two listeners + count = 0; + event(() => null, null, disposables); + event(() => null, null, disposables); + emitter.fire(); + emitter.fire(); + assert.equal(count, 4); // forEach will run *per event* and *per listener* + dispose(disposables); + + // two listeners, with snapshot + count = 0; + const eventSnapshot = Event.snapshot(event); + eventSnapshot(() => null, null, disposables); + eventSnapshot(() => null, null, disposables); + emitter.fire(); + emitter.fire(); + assert.equal(count, 2); // forEach will run only once *per listener* + dispose(disposables); + }); }); diff --git a/src/vs/base/test/node/testUtils.ts b/src/vs/base/test/node/testUtils.ts new file mode 100644 index 00000000000..452e8ae0768 --- /dev/null +++ b/src/vs/base/test/node/testUtils.ts @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { join } from 'vs/base/common/path'; +import { generateUuid } from 'vs/base/common/uuid'; + +export function getRandomTestPath(tmpdir: string, ...segments: string[]): string { + return join(tmpdir, ...segments, generateUuid()); +} diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index b864e628aa8..230992a68a8 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1317,7 +1317,7 @@ export interface DocumentCommentProvider { deleteReaction?(resource: URI, comment: Comment, reaction: CommentReaction, token: CancellationToken): Promise; reactionGroup?: CommentReaction[]; - onDidChangeCommentThreads(): Event; + onDidChangeCommentThreads?(): Event; } /** diff --git a/src/vs/editor/contrib/codeAction/codeAction.ts b/src/vs/editor/contrib/codeAction/codeAction.ts index 226893ae849..0a857df01a8 100644 --- a/src/vs/editor/contrib/codeAction/codeAction.ts +++ b/src/vs/editor/contrib/codeAction/codeAction.ts @@ -28,10 +28,6 @@ export function getCodeActions( trigger: trigger.type === 'manual' ? CodeActionTriggerKind.Manual : CodeActionTriggerKind.Automatic }; - if (filter.kind && CodeActionKind.Source.contains(filter.kind) && rangeOrSelection.isEmpty()) { - rangeOrSelection = model.getFullModelRange(); - } - const promises = getCodeActionProviders(model, filter).map(provider => { return Promise.resolve(provider.provideCodeActions(model, rangeOrSelection, codeActionContext, token)).then(providedCodeActions => { if (!Array.isArray(providedCodeActions)) { diff --git a/src/vs/editor/contrib/codeAction/test/codeAction.test.ts b/src/vs/editor/contrib/codeAction/test/codeAction.test.ts index 060356ae9f0..15db68e279b 100644 --- a/src/vs/editor/contrib/codeAction/test/codeAction.test.ts +++ b/src/vs/editor/contrib/codeAction/test/codeAction.test.ts @@ -12,7 +12,6 @@ import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction'; import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger'; import { IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { ITextModel } from 'vs/editor/common/model'; suite('CodeAction', () => { @@ -217,49 +216,5 @@ suite('CodeAction', () => { assert.strictEqual(actions.length, 0); assert.strictEqual(wasInvoked, false); }); - - test('getCodeActions requests for source actions should expand source actions range to entire document #53525', async function () { - const provider = new class implements CodeActionProvider { - provideCodeActions(model: ITextModel, range: Range): CodeAction[] { - return [{ - title: rangeToString(range), - kind: CodeActionKind.Source.value, - }]; - } - }; - - disposables.push(CodeActionProviderRegistry.register('fooLang', provider)); - - { - const actions = await getCodeActions(model, new Range(1, 1, 1, 1), { - type: 'manual', - filter: { - kind: CodeActionKind.Source, - includeSourceActions: true, - } - }, CancellationToken.None); - assert.strictEqual(actions.length, 1); - assert.strictEqual(actions[0].title, rangeToString(model.getFullModelRange())); - } - - { - const range = new Range(1, 1, 1, 2); - - // But we should not expand for non-empty selections - const actions = await getCodeActions(model, range, { - type: 'manual', - filter: { - kind: CodeActionKind.Source, - includeSourceActions: true, - } - }, CancellationToken.None); - assert.strictEqual(actions.length, 1); - assert.strictEqual(actions[0].title, rangeToString(range)); - } - }); }); -function rangeToString(range: Range): string { - return `${range.startLineNumber},${range.startColumn} ${range.endLineNumber},${range.endColumn} `; -} - diff --git a/src/vs/editor/contrib/find/findWidget.css b/src/vs/editor/contrib/find/findWidget.css index 5b4abbb22d5..b6fbab87454 100644 --- a/src/vs/editor/contrib/find/findWidget.css +++ b/src/vs/editor/contrib/find/findWidget.css @@ -79,9 +79,6 @@ height: 25px; } -.monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input { - width: 100% !important; -} .monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input, .monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input { padding-top: 2px; diff --git a/src/vs/editor/contrib/find/simpleFindWidget.css b/src/vs/editor/contrib/find/simpleFindWidget.css index 078eb737c4b..136970945a4 100644 --- a/src/vs/editor/contrib/find/simpleFindWidget.css +++ b/src/vs/editor/contrib/find/simpleFindWidget.css @@ -39,10 +39,6 @@ flex: 1; } -.monaco-workbench .simple-find-part .monaco-findInput .monaco-inputbox .wrapper .input { - width: 100% !important; -} - .monaco-workbench .simple-find-part .button { min-width: 20px; width: 20px; diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts index 2f52eccc2f5..b863b090377 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts @@ -164,7 +164,7 @@ export class DefinitionAction extends EditorAction { private _openInPeek(editorService: ICodeEditorService, target: ICodeEditor, model: ReferencesModel) { let controller = ReferencesController.get(target); - if (controller) { + if (controller && target.hasModel()) { controller.toggleWidget(target.getSelection(), createCancelablePromise(_ => Promise.resolve(model)), { getMetaTitle: (model) => { return this._getMetaTitle(model); diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts index abb0f9c3575..339cc8c9076 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts @@ -293,7 +293,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC private gotoDefinition(target: IMouseTarget, sideBySide: boolean): Promise { this.editor.setPosition(target.position!); - const action = new DefinitionAction(new DefinitionActionConfig(sideBySide, false, true, false), { alias: undefined, label: undefined, id: undefined, precondition: undefined }); + const action = new DefinitionAction(new DefinitionActionConfig(sideBySide, false, true, false), { alias: '', label: '', id: '', precondition: null }); return this.editor.invokeWithinContext(accessor => action.run(accessor, this.editor)); } diff --git a/src/vs/editor/contrib/gotoError/gotoError.ts b/src/vs/editor/contrib/gotoError/gotoError.ts index f6da3f9a22c..43e17f1a45a 100644 --- a/src/vs/editor/contrib/gotoError/gotoError.ts +++ b/src/vs/editor/contrib/gotoError/gotoError.ts @@ -24,6 +24,8 @@ import { binarySearch } from 'vs/base/common/arrays'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { onUnexpectedError } from 'vs/base/common/errors'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { Action } from 'vs/base/common/actions'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; class MarkerModel { @@ -211,7 +213,8 @@ export class MarkerController implements editorCommon.IEditorContribution { @IMarkerService private readonly _markerService: IMarkerService, @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IThemeService private readonly _themeService: IThemeService, - @ICodeEditorService private readonly _editorService: ICodeEditorService + @ICodeEditorService private readonly _editorService: ICodeEditorService, + @IKeybindingService private readonly _keybindingService: IKeybindingService ) { this._editor = editor; this._widgetVisible = CONTEXT_MARKERS_NAVIGATION_VISIBLE.bindTo(this._contextKeyService); @@ -242,11 +245,18 @@ export class MarkerController implements editorCommon.IEditorContribution { this._model = new MarkerModel(this._editor, markers); this._markerService.onMarkerChanged(this._onMarkerChanged, this, this._disposeOnClose); - this._widget = new MarkerNavigationWidget(this._editor, this._themeService); + const prevMarkerKeybinding = this._keybindingService.lookupKeybinding(PrevMarkerAction.ID); + const nextMarkerKeybinding = this._keybindingService.lookupKeybinding(NextMarkerAction.ID); + const actions = [ + new Action(PrevMarkerAction.ID, PrevMarkerAction.LABEL + (prevMarkerKeybinding ? ` (${prevMarkerKeybinding.getLabel()})` : ''), 'show-previous-problem octicon octicon-chevron-up', this._model.canNavigate(), async () => { if (this._model) { this._model.move(false, true); } }), + new Action(NextMarkerAction.ID, NextMarkerAction.LABEL + (nextMarkerKeybinding ? ` (${nextMarkerKeybinding.getLabel()})` : ''), 'show-next-problem octicon octicon-chevron-down', this._model.canNavigate(), async () => { if (this._model) { this._model.move(true, true); } }) + ]; + this._widget = new MarkerNavigationWidget(this._editor, actions, this._themeService); this._widgetVisible.set(true); this._disposeOnClose.push(this._model); this._disposeOnClose.push(this._widget); + this._disposeOnClose.push(...actions); this._disposeOnClose.push(this._widget.onDidSelectRelatedInformation(related => { this._editorService.openCodeEditor({ resource: related.resource, @@ -410,24 +420,30 @@ class MarkerNavigationAction extends EditorAction { } } -class NextMarkerAction extends MarkerNavigationAction { +export class NextMarkerAction extends MarkerNavigationAction { + static ID: string = 'editor.action.marker.next'; + static LABEL: string = nls.localize('markerAction.next.label', "Go to Next Problem (Error, Warning, Info)"); constructor() { super(true, false, { - id: 'editor.action.marker.next', - label: nls.localize('markerAction.next.label', "Go to Next Problem (Error, Warning, Info)"), + id: NextMarkerAction.ID, + label: NextMarkerAction.LABEL, alias: 'Go to Next Error or Warning', - precondition: EditorContextKeys.writable + precondition: EditorContextKeys.writable, + kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Alt | KeyCode.F8, weight: KeybindingWeight.EditorContrib } }); } } class PrevMarkerAction extends MarkerNavigationAction { + static ID: string = 'editor.action.marker.prev'; + static LABEL: string = nls.localize('markerAction.previous.label', "Go to Previous Problem (Error, Warning, Info)"); constructor() { super(false, false, { - id: 'editor.action.marker.prev', - label: nls.localize('markerAction.previous.label', "Go to Previous Problem (Error, Warning, Info)"), + id: PrevMarkerAction.ID, + label: PrevMarkerAction.LABEL, alias: 'Go to Previous Error or Warning', - precondition: EditorContextKeys.writable + precondition: EditorContextKeys.writable, + kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.F8, weight: KeybindingWeight.EditorContrib } }); } } diff --git a/src/vs/editor/contrib/gotoError/gotoErrorWidget.css b/src/vs/editor/contrib/gotoError/gotoErrorWidget.css index 7ca3f2a86e2..d6db9280ee9 100644 --- a/src/vs/editor/contrib/gotoError/gotoErrorWidget.css +++ b/src/vs/editor/contrib/gotoError/gotoErrorWidget.css @@ -6,7 +6,7 @@ /* marker zone */ .monaco-editor .marker-widget { - padding: 3px 12px; + padding: 8px 12px 0px 20px; text-overflow: ellipsis; white-space: nowrap; } @@ -43,8 +43,7 @@ } .monaco-editor .marker-widget .descriptioncontainer .message .source, -.monaco-editor .marker-widget .descriptioncontainer .message .code, -.monaco-editor .marker-widget .descriptioncontainer .filename { +.monaco-editor .marker-widget .descriptioncontainer .message .code { opacity: 0.6; } diff --git a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts index fd3598b5a28..782d2f63d79 100644 --- a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts +++ b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts @@ -11,9 +11,8 @@ import { IMarker, MarkerSeverity, IRelatedInformation } from 'vs/platform/marker import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/zoneWidget'; -import { registerColor, oneOf } from 'vs/platform/theme/common/colorRegistry'; -import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; +import { registerColor, oneOf, textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; +import { IThemeService, ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; import { AccessibilitySupport } from 'vs/base/common/platform'; import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder, editorInfoForeground, editorInfoBorder } from 'vs/editor/common/view/editorColorRegistry'; @@ -23,6 +22,11 @@ import { ScrollType } from 'vs/editor/common/editorCommon'; import { getBaseLabel, getPathLabel } from 'vs/base/common/labels'; import { isNonEmptyArray } from 'vs/base/common/arrays'; import { Event, Emitter } from 'vs/base/common/event'; +import { PeekViewWidget } from 'vs/editor/contrib/referenceSearch/peekViewWidget'; +import { basename } from 'vs/base/common/resources'; +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'; class MessageWidget { @@ -126,7 +130,7 @@ class MessageWidget { let container = document.createElement('div'); - let relatedResource = document.createElement('span'); + let relatedResource = document.createElement('a'); dom.addClass(relatedResource, 'filename'); relatedResource.innerHTML = `${getBaseLabel(related.resource)}(${related.startLineNumber}, ${related.startColumn}): `; relatedResource.title = getPathLabel(related.resource, undefined); @@ -160,11 +164,10 @@ class MessageWidget { } } -export class MarkerNavigationWidget extends ZoneWidget { +export class MarkerNavigationWidget extends PeekViewWidget { private _parentContainer: HTMLElement; private _container: HTMLElement; - private _title: HTMLElement; private _message: MessageWidget; private _callOnDispose: IDisposable[] = []; private _severity: MarkerSeverity; @@ -175,6 +178,7 @@ export class MarkerNavigationWidget extends ZoneWidget { constructor( editor: ICodeEditor, + private actions: IAction[], private _themeService: IThemeService ) { super(editor, { showArrow: true, showFrame: true, isAccessible: true }); @@ -198,7 +202,10 @@ export class MarkerNavigationWidget extends ZoneWidget { const frameColor = theme.getColor(colorId); this.style({ arrowColor: frameColor, - frameColor: frameColor + frameColor: frameColor, + headerBackgroundColor: this._backgroundColor, + primaryHeadingColor: theme.getColor(peekViewTitleForeground), + secondaryHeadingColor: theme.getColor(peekViewTitleInfoForeground) }); // style() will trigger _applyStyles } @@ -218,7 +225,18 @@ export class MarkerNavigationWidget extends ZoneWidget { this._parentContainer.focus(); } - protected _fillContainer(container: HTMLElement): void { + protected _fillHead(container: HTMLElement): void { + super._fillHead(container); + this._actionbarWidget.push(this.actions, { label: false, icon: true }); + } + + protected _getActionBarOptions(): IActionBarOptions { + return { + orientation: ActionsOrientation.HORIZONTAL_REVERSE + }; + } + + protected _fillBody(container: HTMLElement): void { this._parentContainer = container; dom.addClass(container, 'marker-widget'); this._parentContainer.tabIndex = 0; @@ -227,10 +245,6 @@ export class MarkerNavigationWidget extends ZoneWidget { this._container = document.createElement('div'); container.appendChild(this._container); - this._title = document.createElement('div'); - this._title.className = 'block title'; - this._container.appendChild(this._title); - this._message = new MessageWidget(this._container, this.editor, related => this._onDidSelectRelatedInformation.fire(related)); this._disposables.push(this._message); } @@ -244,7 +258,6 @@ export class MarkerNavigationWidget extends ZoneWidget { // * title // * message this._container.classList.remove('stale'); - this._title.innerHTML = nls.localize('title.wo_source', "({0}/{1})", markerIdx, markerCount); this._message.update(marker); // update frame color (only applied on 'show') @@ -257,6 +270,14 @@ export class MarkerNavigationWidget extends ZoneWidget { let position = editorPosition && range.containsPosition(editorPosition) ? editorPosition : range.getStartPosition(); super.show(position, this.computeRequiredHeight()); + const detail = markerCount > 1 + ? nls.localize('problems', "{0} of {1} problems", markerIdx, markerCount) + : nls.localize('change', "{0} of {1} problem", markerIdx, markerCount); + const model = this.editor.getModel(); + if (model) { + this.setTitle(basename(model.uri), detail); + } + this.editor.revealPositionInCenter(position, ScrollType.Smooth); if (this.editor.getConfiguration().accessibilitySupport !== AccessibilitySupport.Disabled) { @@ -274,7 +295,8 @@ export class MarkerNavigationWidget extends ZoneWidget { this._relayout(); } - protected _doLayout(heightInPixel: number, widthInPixel: number): void { + protected _doLayoutBody(heightInPixel: number, widthInPixel: number): void { + super._doLayoutBody(heightInPixel, widthInPixel); this._message.layout(heightInPixel, widthInPixel); this._container.style.height = `${heightInPixel}px`; } @@ -284,7 +306,7 @@ export class MarkerNavigationWidget extends ZoneWidget { } private computeRequiredHeight() { - return 1 + this._message.getHeightInLines(); + return 3 + this._message.getHeightInLines(); } } @@ -298,3 +320,10 @@ export const editorMarkerNavigationError = registerColor('editorMarkerNavigation export const editorMarkerNavigationWarning = registerColor('editorMarkerNavigationWarning.background', { dark: warningDefault, light: warningDefault, hc: warningDefault }, nls.localize('editorMarkerNavigationWarning', 'Editor marker navigation widget warning color.')); export const editorMarkerNavigationInfo = registerColor('editorMarkerNavigationInfo.background', { dark: infoDefault, light: infoDefault, hc: infoDefault }, nls.localize('editorMarkerNavigationInfo', 'Editor marker navigation widget info color.')); export const editorMarkerNavigationBackground = registerColor('editorMarkerNavigation.background', { dark: '#2D2D30', light: Color.white, hc: '#0C141F' }, nls.localize('editorMarkerNavigationBackground', 'Editor marker navigation widget background.')); + +registerThemingParticipant((theme, collector) => { + const link = theme.getColor(textLinkForeground); + if (link) { + collector.addRule(`.monaco-editor .marker-widget a { color: ${link}; }`); + } +}); diff --git a/src/vs/editor/contrib/hover/hover.css b/src/vs/editor/contrib/hover/hover.css index 6aa31e6e1fc..41f6a72c725 100644 --- a/src/vs/editor/contrib/hover/hover.css +++ b/src/vs/editor/contrib/hover/hover.css @@ -23,7 +23,7 @@ display: none; } -.monaco-editor-hover .hover-row { +.monaco-editor-hover .hover-contents { padding: 4px 8px; } @@ -72,39 +72,12 @@ word-break: break-all; } -.monaco-editor-hover .marker-hover { +.monaco-editor-hover .hover-row .actions { display: flex; + padding: 2px 0px; } -.monaco-editor-hover .marker-hover > .marker { - flex: 1; -} - -.monaco-editor-hover .marker-hover > .actions { - padding-left: 12px; - display: flex; -} - -.monaco-editor-hover .marker-hover > .actions > .icon { - width: 16px; - height: 16px; -} - -.monaco-editor-hover .marker-hover > .actions .action { +.monaco-editor-hover .hover-row .actions .action { cursor: pointer; - padding-left: 4px; -} - -.monaco-editor-hover .marker-hover > .actions > .peek-marker { - font-size: large; - vertical-align: middle; -} - -.monaco-editor-hover .marker-hover > .actions > .light-bulb { - background: url('../codeAction/lightbulb.svg') center center no-repeat; -} - -.hc-black .monaco-editor-hover .marker-hover > .actions > .light-bulb, -.vs-dark .monaco-editor-hover .marker-hover > .actions > .light-bulb { - background: url('../codeAction/lightbulb-dark.svg') center center no-repeat; -} + padding-left: 8px; +} \ No newline at end of file diff --git a/src/vs/editor/contrib/hover/hover.ts b/src/vs/editor/contrib/hover/hover.ts index 93192a81278..cc331c3e41e 100644 --- a/src/vs/editor/contrib/hover/hover.ts +++ b/src/vs/editor/contrib/hover/hover.ts @@ -23,12 +23,10 @@ import { ModesGlyphHoverWidget } from 'vs/editor/contrib/hover/modesGlyphHover'; import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { editorHoverBackground, editorHoverBorder, editorHoverHighlight, textCodeBlockBackground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; +import { editorHoverBackground, editorHoverBorder, editorHoverHighlight, textCodeBlockBackground, textLinkForeground, editorHoverFooterBackground } from 'vs/platform/theme/common/colorRegistry'; import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; -import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; -import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; export class ModesHoverController implements IEditorContribution { @@ -65,11 +63,9 @@ export class ModesHoverController implements IEditorContribution { constructor(private readonly _editor: ICodeEditor, @IOpenerService private readonly _openerService: IOpenerService, - @IContextMenuService private readonly _contextMenuService: IContextMenuService, - @IBulkEditService private readonly _bulkEditService: IBulkEditService, - @ICommandService private readonly _commandService: ICommandService, @IModeService private readonly _modeService: IModeService, @IMarkerDecorationsService private readonly _markerDecorationsService: IMarkerDecorationsService, + @IKeybindingService private readonly _keybindingService: IKeybindingService, @IThemeService private readonly _themeService: IThemeService ) { this._toUnhook = []; @@ -213,7 +209,7 @@ export class ModesHoverController implements IEditorContribution { private _createHoverWidget() { const renderer = new MarkdownRenderer(this._editor, this._modeService, this._openerService); - this._contentWidget = new ModesContentHoverWidget(this._editor, renderer, this._markerDecorationsService, this._themeService, this._contextMenuService, this._bulkEditService, this._commandService, this._openerService); + this._contentWidget = new ModesContentHoverWidget(this._editor, renderer, this._markerDecorationsService, this._themeService, this._keybindingService, this._openerService); this._glyphWidget = new ModesGlyphHoverWidget(this._editor, renderer); } @@ -295,6 +291,10 @@ registerThemingParticipant((theme, collector) => { collector.addRule(`.monaco-editor .monaco-editor-hover hr { border-top: 1px solid ${hoverBorder.transparent(0.5)}; }`); collector.addRule(`.monaco-editor .monaco-editor-hover hr { border-bottom: 0px solid ${hoverBorder.transparent(0.5)}; }`); } + const actionsBackground = theme.getColor(editorHoverFooterBackground); + if (actionsBackground) { + collector.addRule(`.monaco-editor .monaco-editor-hover .hover-row .actions { background-color: ${actionsBackground}; }`); + } const link = theme.getColor(textLinkForeground); if (link) { collector.addRule(`.monaco-editor .monaco-editor-hover a { color: ${link}; }`); diff --git a/src/vs/editor/contrib/hover/modesContentHover.ts b/src/vs/editor/contrib/hover/modesContentHover.ts index 11e8475733f..1672539f7c3 100644 --- a/src/vs/editor/contrib/hover/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/modesContentHover.ts @@ -8,7 +8,7 @@ import * as dom from 'vs/base/browser/dom'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Color, RGBA } from 'vs/base/common/color'; import { IMarkdownString, MarkdownString, isEmptyMarkdownString, markedStringsEquals } from 'vs/base/common/htmlContent'; -import { Disposable, IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; @@ -29,15 +29,8 @@ import { basename } from 'vs/base/common/resources'; import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; import { onUnexpectedError } from 'vs/base/common/errors'; import { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener'; -import { MarkerController } from 'vs/editor/contrib/gotoError/gotoError'; -import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction'; -import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger'; -import { Action } from 'vs/base/common/actions'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { applyCodeAction } from 'vs/editor/contrib/codeAction/codeActionCommands'; -import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; -import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; +import { MarkerController, NextMarkerAction } from 'vs/editor/contrib/gotoError/gotoError'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; const $ = dom.$; @@ -215,9 +208,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { markdownRenderer: MarkdownRenderer, markerDecorationsService: IMarkerDecorationsService, private readonly _themeService: IThemeService, - private readonly _contextMenuService: IContextMenuService, - private readonly _bulkEditService: IBulkEditService, - private readonly _commandService: ICommandService, + private readonly _keybindingService: IKeybindingService, private readonly _openerService: IOpenerService | null = NullOpenerService, ) { super(ModesContentHoverWidget.ID, editor); @@ -356,6 +347,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { let containColorPicker = false; let markdownDisposeable: IDisposable; + const markerMessages: MarkerHover[] = []; messages.forEach((msg) => { if (!msg.range) { return; @@ -449,21 +441,23 @@ export class ModesContentHoverWidget extends ContentHoverWidget { }); } else { if (msg instanceof MarkerHover) { + markerMessages.push(msg); isEmptyHoverContent = false; - fragment.appendChild($('div.hover-row', undefined, this.renderMarkerHover(msg))); } else { msg.contents .filter(contents => !isEmptyMarkdownString(contents)) .forEach(contents => { const renderedContents = this._markdownRenderer.render(contents); markdownDisposeable = renderedContents; - fragment.appendChild($('div.hover-row', undefined, renderedContents.element)); + fragment.appendChild($('div.hover-row.hover-contents', undefined, renderedContents.element)); isEmptyHoverContent = false; }); } } }); + markerMessages.forEach(msg => fragment.appendChild(this.renderMarkerHover(msg))); + // show if (!containColorPicker && !isEmptyHoverContent) { @@ -480,13 +474,14 @@ export class ModesContentHoverWidget extends ContentHoverWidget { } private renderMarkerHover(markerHover: MarkerHover): HTMLElement { - const hoverElement = $('div.marker-hover'); - const markerElement = dom.append(hoverElement, $('div.marker')); + const hoverElement = $('div.hover-row'); + const markerElement = dom.append(hoverElement, $('div.marker.hover-contents')); const { source, message, code, relatedInformation } = markerHover.marker; const messageElement = dom.append(markerElement, $('span')); messageElement.style.whiteSpace = 'pre-wrap'; messageElement.innerText = message; + this._editor.applyFontInfo(messageElement); if (source || code) { const detailsElement = dom.append(markerElement, $('span')); @@ -500,7 +495,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { const relatedInfoContainer = dom.append(markerElement, $('div')); relatedInfoContainer.style.marginTop = '8px'; const a = dom.append(relatedInfoContainer, $('a')); - a.innerText = `${basename(resource)}(${startLineNumber}, ${startColumn})`; + a.innerText = `${basename(resource)}(${startLineNumber}, ${startColumn}): `; a.style.cursor = 'pointer'; a.onclick = e => { e.stopPropagation(); @@ -510,27 +505,17 @@ export class ModesContentHoverWidget extends ContentHoverWidget { } }; const messageElement = dom.append(relatedInfoContainer, $('span')); - messageElement.innerText = `: ${message}`; + messageElement.innerText = message; + this._editor.applyFontInfo(messageElement); } } const actionsElement = dom.append(hoverElement, $('div.actions')); - const showCodeActions = dom.append(actionsElement, $('a.action.icon.light-bulb', { title: nls.localize('code actions', "Show Fixes...") })); const disposables: IDisposable[] = []; - disposables.push(dom.addDisposableListener(showCodeActions, dom.EventType.CLICK, async e => { - e.stopPropagation(); - e.preventDefault(); - const codeActionsPromise = this.getCodeActions(markerHover.marker); - disposables.push(toDisposable(() => codeActionsPromise.cancel())); - const actions = await codeActionsPromise; - const elementPosition = dom.getDomNodePagePosition(showCodeActions); - this._contextMenuService.showContextMenu({ - getAnchor: () => ({ x: elementPosition.left + 6, y: elementPosition.top + elementPosition.height + 6 }), - getActions: () => actions - }); - })); - const peekMarkerAction = dom.append(actionsElement, $('a.action.icon.peek-marker', { title: nls.localize('go to problem', "Go to Problem") })); - peekMarkerAction.textContent = '↪'; + const keybinding = this._keybindingService.lookupKeybinding(NextMarkerAction.ID); + const label = nls.localize('peek problem', "Peek Problem") + (keybinding ? ` (${keybinding.getLabel()})` : ''); + const peekMarkerAction = dom.append(actionsElement, $('a.action.peek-marker', { title: label })); + peekMarkerAction.textContent = label; disposables.push(dom.addDisposableListener(peekMarkerAction, dom.EventType.CLICK, e => { e.stopPropagation(); e.preventDefault(); @@ -542,23 +527,6 @@ export class ModesContentHoverWidget extends ContentHoverWidget { return hoverElement; } - private getCodeActions(marker: IMarker): CancelablePromise { - return createCancelablePromise(async cancellationToken => { - const codeActions = await getCodeActions(this._editor.getModel()!, new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn), { type: 'manual', filter: { kind: CodeActionKind.QuickFix } }, cancellationToken); - if (codeActions.length) { - return codeActions.map(codeAction => new Action( - codeAction.command ? codeAction.command.id : codeAction.title, - codeAction.title, - undefined, - true, - () => applyCodeAction(codeAction, this._bulkEditService, this._commandService))); - } - return [ - new Action('', nls.localize('editor.action.quickFix.noneMessage', "No code actions available")) - ]; - }); - } - private static readonly _DECORATION_OPTIONS = ModelDecorationOptions.register({ className: 'hoverHighlight' }); diff --git a/src/vs/editor/contrib/referenceSearch/referencesController.ts b/src/vs/editor/contrib/referenceSearch/referencesController.ts index 39646d1713d..6cd7323f6c6 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesController.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesController.ts @@ -33,8 +33,8 @@ export abstract class ReferencesController implements editorCommon.IEditorContri private static readonly ID = 'editor.contrib.referencesController'; private _editor: ICodeEditor; - private _widget: ReferenceWidget; - private _model: ReferencesModel; + private _widget: ReferenceWidget | null; + private _model: ReferencesModel | null; private _requestIdPool = 0; private _disposables: IDisposable[] = []; private _ignoreModelChangeEvent = false; @@ -66,23 +66,26 @@ export abstract class ReferencesController implements editorCommon.IEditorContri public dispose(): void { this._referenceSearchVisible.reset(); dispose(this._disposables); - dispose(this._widget); - dispose(this._model); - this._widget = null; - this._model = null; - this._editor = null; + if (this._widget) { + dispose(this._widget); + this._widget = null; + } + if (this._model) { + dispose(this._model); + this._model = null; + } } public toggleWidget(range: Range, modelPromise: CancelablePromise, options: RequestOptions): void { // close current widget and return early is position didn't change - let widgetPosition: Position; + let widgetPosition: Position | undefined; if (this._widget) { widgetPosition = this._widget.position; } this.closeWidget(); if (!!widgetPosition && range.containsPosition(widgetPosition)) { - return null; + return; } this._referenceSearchVisible.set(true); @@ -101,9 +104,10 @@ export abstract class ReferencesController implements editorCommon.IEditorContri this._widget.show(range); this._disposables.push(this._widget.onDidClose(() => { modelPromise.cancel(); - - this._storageService.store(storageKey, JSON.stringify(this._widget.layoutData), StorageScope.GLOBAL); - this._widget = null; + if (this._widget) { + this._storageService.store(storageKey, JSON.stringify(this._widget.layoutData), StorageScope.GLOBAL); + this._widget = null; + } this.closeWidget(); })); @@ -119,13 +123,17 @@ export abstract class ReferencesController implements editorCommon.IEditorContri break; } case 'side': - this.openReference(element, kind === 'side'); + if (element) { + this.openReference(element, kind === 'side'); + } break; case 'goto': - if (options.onGoto) { - options.onGoto(element); - } else { - this._gotoReference(element); + if (element) { + if (options.onGoto) { + options.onGoto(element); + } else { + this._gotoReference(element); + } } break; } @@ -148,7 +156,7 @@ export abstract class ReferencesController implements editorCommon.IEditorContri // show widget return this._widget.setModel(this._model).then(() => { - if (this._widget) { // might have been closed + if (this._widget && this._model && this._editor.hasModel()) { // might have been closed // set title this._widget.setMetaTitle(options.getMetaTitle(this._model)); @@ -169,31 +177,46 @@ export abstract class ReferencesController implements editorCommon.IEditorContri } public async goToNextOrPreviousReference(fwd: boolean) { - if (this._model) { // can be called while still resolving... - let source = this._model.nearestReference(this._editor.getModel().uri, this._widget.position); - let target = this._model.nextOrPreviousReference(source, fwd); - let editorFocus = this._editor.hasTextFocus(); - await this._widget.setSelection(target); - await this._gotoReference(target); - if (editorFocus) { - this._editor.focus(); - } + if (!this._editor.hasModel() || !this._model || !this._widget) { + // can be called while still resolving... + return; + } + const currentPosition = this._widget.position; + if (!currentPosition) { + return; + } + const source = this._model.nearestReference(this._editor.getModel().uri, currentPosition); + if (!source) { + return; + } + const target = this._model.nextOrPreviousReference(source, fwd); + const editorFocus = this._editor.hasTextFocus(); + await this._widget.setSelection(target); + await this._gotoReference(target); + if (editorFocus) { + this._editor.focus(); } } public closeWidget(): void { - dispose(this._widget); - this._widget = null; + if (this._widget) { + dispose(this._widget); + this._widget = null; + } this._referenceSearchVisible.reset(); this._disposables = dispose(this._disposables); - dispose(this._model); - this._model = null; + if (this._model) { + dispose(this._model); + this._model = null; + } this._editor.focus(); this._requestIdPool += 1; // Cancel pending requests } private _gotoReference(ref: Location): Promise { - this._widget.hide(); + if (this._widget) { + this._widget.hide(); + } this._ignoreModelChangeEvent = true; const range = Range.lift(ref.range).collapseToStart(); @@ -216,8 +239,10 @@ export abstract class ReferencesController implements editorCommon.IEditorContri return; } - this._widget.show(range); - this._widget.focus(); + if (this._widget) { + this._widget.show(range); + this._widget.focus(); + } }, (err) => { this._ignoreModelChangeEvent = false; diff --git a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts index 4fd0bbebf59..782e184fa6d 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts @@ -461,14 +461,14 @@ export class ReferenceWidget extends PeekViewWidget { }); } - public setModel(newModel: ReferencesModel | undefined): Promise | undefined { + public setModel(newModel: ReferencesModel | undefined): Promise { // clean up this._disposeOnNewModel = dispose(this._disposeOnNewModel); this._model = newModel; if (this._model) { return this._onNewModel(); } - return undefined; + return Promise.resolve(); } private _onNewModel(): Promise { 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 feefaef22d0..a3c8566e896 100644 --- a/src/vs/platform/backup/test/electron-main/backupMainService.test.ts +++ b/src/vs/platform/backup/test/electron-main/backupMainService.test.ts @@ -19,7 +19,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/ import { ConsoleLogMainService } from 'vs/platform/log/common/log'; import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { createHash } from 'crypto'; -import { getRandomTestPath } from 'vs/workbench/test/workbenchTestServices'; +import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { Schemas } from 'vs/base/common/network'; suite('BackupMainService', () => { @@ -252,7 +252,7 @@ suite('BackupMainService', () => { const emptyBackups = service.getEmptyWindowBackupPaths(); assert.equal(1, emptyBackups.length); - assert.equal(1, fs.readdirSync(path.join(backupHome, emptyBackups[0].backupFolder)).length); + assert.equal(1, fs.readdirSync(path.join(backupHome, emptyBackups[0].backupFolder!)).length); }); suite('migrate path to URI', () => { diff --git a/src/vs/platform/contextkey/common/contextkeys.ts b/src/vs/platform/contextkey/common/contextkeys.ts index 6697e0d989b..130a736dc15 100644 --- a/src/vs/platform/contextkey/common/contextkeys.ts +++ b/src/vs/platform/contextkey/common/contextkeys.ts @@ -8,9 +8,14 @@ import { isMacintosh, isLinux, isWindows } from 'vs/base/common/platform'; export const InputFocusedContextKey = 'inputFocus'; export const InputFocusedContext = new RawContextKey(InputFocusedContextKey, false); + export const IsMacContext = new RawContextKey('isMac', isMacintosh); export const IsLinuxContext = new RawContextKey('isLinux', isLinux); export const IsWindowsContext = new RawContextKey('isWindows', isWindows); +export const HasMacNativeTabsContext = new RawContextKey('hasMacNativeTabs', false); + export const SupportsWorkspacesContext = new RawContextKey('supportsWorkspaces', true); export const SupportsOpenFileFolderContext = new RawContextKey('supportsOpenFileFolder', isMacintosh); + +export const IsDevelopmentContext = new RawContextKey('isDevelopment', false); diff --git a/src/vs/platform/extensionManagement/test/electron-browser/extensionEnablementService.test.ts b/src/vs/platform/extensionManagement/test/electron-browser/extensionEnablementService.test.ts index 65c7ea1b099..5e845197eb6 100644 --- a/src/vs/platform/extensionManagement/test/electron-browser/extensionEnablementService.test.ts +++ b/src/vs/platform/extensionManagement/test/electron-browser/extensionEnablementService.test.ts @@ -10,8 +10,7 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/ import { Emitter } from 'vs/base/common/event'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IStorageService } from 'vs/platform/storage/common/storage'; -import { TestStorageService } from 'vs/workbench/test/workbenchTestServices'; +import { IStorageService, InMemoryStorageService } from 'vs/platform/storage/common/storage'; import { IExtensionContributions, ExtensionType, IExtension } from 'vs/platform/extensions/common/extensions'; import { isUndefinedOrNull } from 'vs/base/common/types'; @@ -24,7 +23,7 @@ function storageService(instantiationService: TestInstantiationService): IStorag getWorkbenchState: () => WorkbenchState.FOLDER, }); } - service = instantiationService.stub(IStorageService, new TestStorageService()); + service = instantiationService.stub(IStorageService, new InMemoryStorageService()); } return service; } diff --git a/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts b/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts index 1b9af7cde94..6106afdb08f 100644 --- a/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts +++ b/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts @@ -8,7 +8,7 @@ import * as os from 'os'; import * as extfs from 'vs/base/node/extfs'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { parseArgs } from 'vs/platform/environment/node/argv'; -import { getRandomTestPath } from 'vs/workbench/test/workbenchTestServices'; +import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { join } from 'vs/base/common/path'; import { mkdirp } from 'vs/base/node/pfs'; import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/node/extensionGalleryService'; diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index b1626237c58..3603d734588 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -101,6 +101,7 @@ export const WorkbenchListMultiSelection = new RawContextKey('listMulti export const WorkbenchListSupportsKeyboardNavigation = new RawContextKey('listSupportsKeyboardNavigation', true); export const WorkbenchListAutomaticKeyboardNavigationKey = 'listAutomaticKeyboardNavigation'; export const WorkbenchListAutomaticKeyboardNavigation = new RawContextKey(WorkbenchListAutomaticKeyboardNavigationKey, true); +export let didBindWorkbenchListAutomaticKeyboardNavigation = false; function createScopedContextKeyService(contextKeyService: IContextKeyService, widget: ListWidget): IContextKeyService { const result = contextKeyService.createScoped(widget.getHTMLElement()); @@ -112,6 +113,7 @@ export const multiSelectModifierSettingKey = 'workbench.list.multiSelectModifier export const openModeSettingKey = 'workbench.list.openMode'; export const horizontalScrollingKey = 'workbench.tree.horizontalScrolling'; export const keyboardNavigationSettingKey = 'workbench.list.keyboardNavigation'; +export const automaticKeyboardNavigationSettingKey = 'workbench.list.automaticKeyboardNavigation'; const treeIndentKey = 'workbench.tree.indent'; function useAltAsMultipleSelectionModifier(configurationService: IConfigurationService): boolean { @@ -649,6 +651,7 @@ export interface IOpenEvent { editorOptions: IEditorOptions; sideBySide: boolean; element: T; + browserEvent?: UIEvent; } export interface IResourceResultsNavigationOptions { @@ -698,7 +701,7 @@ export class TreeResourceNavigator2 extends Disposable { const isMouseEvent = e.browserEvent && e.browserEvent instanceof MouseEvent; if (!isMouseEvent) { - this.open(true, false, false); + this.open(true, false, false, e.browserEvent); } } @@ -716,11 +719,11 @@ export class TreeResourceNavigator2 extends Disposable { if (this.tree.openOnSingleClick || isDoubleClick || isKeyboardEvent) { const sideBySide = e.browserEvent instanceof MouseEvent && (e.browserEvent.ctrlKey || e.browserEvent.metaKey || e.browserEvent.altKey); - this.open(preserveFocus, isDoubleClick || isMiddleClick, sideBySide); + this.open(preserveFocus, isDoubleClick || isMiddleClick, sideBySide, e.browserEvent); } } - private open(preserveFocus: boolean, pinned: boolean, sideBySide: boolean): void { + private open(preserveFocus: boolean, pinned: boolean, sideBySide: boolean, browserEvent?: UIEvent): void { this._onDidOpenResource.fire({ editorOptions: { preserveFocus, @@ -728,7 +731,8 @@ export class TreeResourceNavigator2 extends Disposable { revealIfVisible: true }, sideBySide, - element: this.tree.getSelection()[0] + element: this.tree.getSelection()[0], + browserEvent }); } } @@ -778,9 +782,23 @@ export class WorkbenchObjectTree, TFilterData = void> @IKeybindingService keybindingService: IKeybindingService ) { WorkbenchListSupportsKeyboardNavigation.bindTo(contextKeyService); - WorkbenchListAutomaticKeyboardNavigation.bindTo(contextKeyService); - const automaticKeyboardNavigation = contextKeyService.getContextKeyValue(WorkbenchListAutomaticKeyboardNavigationKey); + if (!didBindWorkbenchListAutomaticKeyboardNavigation) { + WorkbenchListAutomaticKeyboardNavigation.bindTo(contextKeyService); + didBindWorkbenchListAutomaticKeyboardNavigation = true; + } + + const getAutomaticKeyboardNavigation = () => { + // give priority to the context key value to disable this completely + let automaticKeyboardNavigation = contextKeyService.getContextKeyValue(WorkbenchListAutomaticKeyboardNavigationKey); + + if (automaticKeyboardNavigation) { + automaticKeyboardNavigation = configurationService.getValue(automaticKeyboardNavigationSettingKey); + } + + return automaticKeyboardNavigation; + }; + const keyboardNavigation = configurationService.getValue(keyboardNavigationSettingKey); const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : configurationService.getValue(horizontalScrollingKey); const openOnSingleClick = useSingleClickToOpen(configurationService); @@ -792,7 +810,7 @@ export class WorkbenchObjectTree, TFilterData = void> ...computeStyles(themeService.getTheme(), defaultListStyles), ...workbenchListOptions, indent: configurationService.getValue(treeIndentKey), - automaticKeyboardNavigation, + automaticKeyboardNavigation: getAutomaticKeyboardNavigation(), simpleKeyboardNavigation: keyboardNavigation === 'simple', filterOnType: keyboardNavigation === 'filter', horizontalScrolling, @@ -852,13 +870,13 @@ export class WorkbenchObjectTree, TFilterData = void> filterOnType: keyboardNavigation === 'filter' }); } + if (e.affectsConfiguration(automaticKeyboardNavigationSettingKey)) { + this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() }); + } }), this.contextKeyService.onDidChangeContext(e => { if (e.affectsSome(interestingContextKeys)) { - const automaticKeyboardNavigation = this.contextKeyService.getContextKeyValue(WorkbenchListAutomaticKeyboardNavigationKey); - this.updateOptions({ - automaticKeyboardNavigation - }); + this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() }); } }) ); @@ -897,9 +915,23 @@ export class WorkbenchDataTree extends DataTree(WorkbenchListAutomaticKeyboardNavigationKey); + if (!didBindWorkbenchListAutomaticKeyboardNavigation) { + WorkbenchListAutomaticKeyboardNavigation.bindTo(contextKeyService); + didBindWorkbenchListAutomaticKeyboardNavigation = true; + } + + const getAutomaticKeyboardNavigation = () => { + // give priority to the context key value to disable this completely + let automaticKeyboardNavigation = contextKeyService.getContextKeyValue(WorkbenchListAutomaticKeyboardNavigationKey); + + if (automaticKeyboardNavigation) { + automaticKeyboardNavigation = configurationService.getValue(automaticKeyboardNavigationSettingKey); + } + + return automaticKeyboardNavigation; + }; + const keyboardNavigation = configurationService.getValue(keyboardNavigationSettingKey); const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : configurationService.getValue(horizontalScrollingKey); const openOnSingleClick = useSingleClickToOpen(configurationService); @@ -911,7 +943,7 @@ export class WorkbenchDataTree extends DataTree extends DataTree { if (e.affectsSome(interestingContextKeys)) { - const automaticKeyboardNavigation = this.contextKeyService.getContextKeyValue(WorkbenchListAutomaticKeyboardNavigationKey); - this.updateOptions({ - automaticKeyboardNavigation - }); + this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() }); } }) ); @@ -1011,9 +1043,23 @@ export class WorkbenchAsyncDataTree extends Async @IKeybindingService keybindingService: IKeybindingService ) { WorkbenchListSupportsKeyboardNavigation.bindTo(contextKeyService); - WorkbenchListAutomaticKeyboardNavigation.bindTo(contextKeyService); - const automaticKeyboardNavigation = contextKeyService.getContextKeyValue(WorkbenchListAutomaticKeyboardNavigationKey); + if (!didBindWorkbenchListAutomaticKeyboardNavigation) { + WorkbenchListAutomaticKeyboardNavigation.bindTo(contextKeyService); + didBindWorkbenchListAutomaticKeyboardNavigation = true; + } + + const getAutomaticKeyboardNavigation = () => { + // give priority to the context key value to disable this completely + let automaticKeyboardNavigation = contextKeyService.getContextKeyValue(WorkbenchListAutomaticKeyboardNavigationKey); + + if (automaticKeyboardNavigation) { + automaticKeyboardNavigation = configurationService.getValue(automaticKeyboardNavigationSettingKey); + } + + return automaticKeyboardNavigation; + }; + const keyboardNavigation = configurationService.getValue(keyboardNavigationSettingKey); const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : configurationService.getValue(horizontalScrollingKey); const openOnSingleClick = useSingleClickToOpen(configurationService); @@ -1025,7 +1071,7 @@ export class WorkbenchAsyncDataTree extends Async ...computeStyles(themeService.getTheme(), defaultListStyles), ...workbenchListOptions, indent: configurationService.getValue(treeIndentKey), - automaticKeyboardNavigation, + automaticKeyboardNavigation: getAutomaticKeyboardNavigation(), simpleKeyboardNavigation: keyboardNavigation === 'simple', filterOnType: keyboardNavigation === 'filter', horizontalScrolling, @@ -1085,13 +1131,13 @@ export class WorkbenchAsyncDataTree extends Async filterOnType: keyboardNavigation === 'filter' }); } + if (e.affectsConfiguration(automaticKeyboardNavigationSettingKey)) { + this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() }); + } }), this.contextKeyService.onDidChangeContext(e => { if (e.affectsSome(interestingContextKeys)) { - const automaticKeyboardNavigation = this.contextKeyService.getContextKeyValue(WorkbenchListAutomaticKeyboardNavigationKey); - this.updateOptions({ - automaticKeyboardNavigation - }); + this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() }); } }) ); @@ -1158,5 +1204,10 @@ configurationRegistry.registerConfiguration({ 'default': 'highlight', 'description': localize('keyboardNavigationSettingKey', "Controls the keyboard navigation style for lists and trees in the workbench. Can be simple, highlight and filter.") }, + [automaticKeyboardNavigationSettingKey]: { + 'type': 'boolean', + 'default': true, + 'description': localize('automatic keyboard navigation setting', "Controls whether keyboard navigation in lists and trees is automatically triggered simply by typing. If set to `false`, keyboard navigation is only triggered when executing the `list.toggleKeyboardNavigation` command, for which you can assign a keyboard shortcut.") + } } }); diff --git a/src/vs/platform/quickinput/common/quickInput.ts b/src/vs/platform/quickinput/common/quickInput.ts index f19d33f8318..1c4a59befac 100644 --- a/src/vs/platform/quickinput/common/quickInput.ts +++ b/src/vs/platform/quickinput/common/quickInput.ts @@ -52,6 +52,16 @@ export interface IPickOptions { */ matchOnDetail?: boolean; + /** + * an optional flag to filter the picks based on label. Defaults to true. + */ + matchOnLabel?: boolean; + + /** + * an option flag to control whether focus is always automatically brought to a list item. Defaults to true. + */ + autoFocusOnList?: boolean; + /** * an optional flag to not close the picker on focus lost */ @@ -166,6 +176,10 @@ export interface IQuickPick extends IQuickInput { matchOnDetail: boolean; + matchOnLabel: boolean; + + autoFocusOnList: boolean; + quickNavigate: IQuickNavigateConfiguration | undefined; activeItems: ReadonlyArray; diff --git a/src/vs/platform/remote/node/remoteAgentConnection.ts b/src/vs/platform/remote/node/remoteAgentConnection.ts index 2ab02017c16..bfbe7b3f58d 100644 --- a/src/vs/platform/remote/node/remoteAgentConnection.ts +++ b/src/vs/platform/remote/node/remoteAgentConnection.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { Client, BufferedProtocol } from 'vs/base/parts/ipc/node/ipc.net'; -import { IExtensionHostDebugParams } from 'vs/platform/environment/common/environment'; export interface RemoteAgentConnectionContext { remoteAuthority: string; @@ -20,10 +19,14 @@ export interface IExtensionHostConnectionResult { debugPort?: number; } -export interface IRemoteExtensionHostDebugParams extends IExtensionHostDebugParams { +export interface IRemoteExtensionHostStartParams { + language: string; + debugId?: string; + break: boolean; + port: number | null; updatePort?: boolean; } -export function connectRemoteAgentExtensionHost(host: string, port: number, debugArguments: IRemoteExtensionHostDebugParams, isBuilt: boolean): Promise { +export function connectRemoteAgentExtensionHost(host: string, port: number, startArguments: IRemoteExtensionHostStartParams, isBuilt: boolean): Promise { throw new Error(`Not implemented`); } diff --git a/src/vs/platform/state/test/node/state.test.ts b/src/vs/platform/state/test/node/state.test.ts index abb30e484a9..0f071932b30 100644 --- a/src/vs/platform/state/test/node/state.test.ts +++ b/src/vs/platform/state/test/node/state.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import * as os from 'os'; import * as path from 'vs/base/common/path'; import * as extfs from 'vs/base/node/extfs'; -import { getRandomTestPath } from 'vs/workbench/test/workbenchTestServices'; +import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { FileStorage } from 'vs/platform/state/node/stateService'; suite('StateService', () => { diff --git a/src/vs/platform/storage/node/storageMainService.ts b/src/vs/platform/storage/node/storageMainService.ts index e5d43414b64..e074847ef54 100644 --- a/src/vs/platform/storage/node/storageMainService.ts +++ b/src/vs/platform/storage/node/storageMainService.ts @@ -222,6 +222,10 @@ export class StorageMainService extends Disposable implements IStorageMainServic 'update/updateNotificationTime' ].forEach(key => supportedKeys.set(key.toLowerCase(), key)); + // https://github.com/Microsoft/vscode/issues/68468 + const wellKnownPublishers = ['Microsoft', 'GitHub']; + const wellKnownExtensions = ['ms-vscode.Go', 'WallabyJs.quokka-vscode', 'Telerik.nativescript', 'Shan.code-settings-sync', 'ritwickdey.LiveServer', 'PKief.material-icon-theme', 'PeterJausovec.vscode-docker', 'ms-vscode.PowerShell', 'LaurentTreguier.vscode-simple-icons', 'KnisterPeter.vscode-github', 'DotJoshJohnson.xml', 'Dart-Code.dart-code', 'alefragnani.Bookmarks']; + // Support extension storage as well (always the ID of the extension) extensions.forEach(extension => { let extensionId: string; @@ -232,6 +236,22 @@ export class StorageMainService extends Disposable implements IStorageMainServic } if (extensionId) { + for (let i = 0; i < wellKnownPublishers.length; i++) { + const publisher = wellKnownPublishers[i]; + if (startsWith(extensionId, `${publisher.toLowerCase()}.`)) { + extensionId = `${publisher}${extensionId.substr(publisher.length)}`; + break; + } + } + + for (let j = 0; j < wellKnownExtensions.length; j++) { + const wellKnownExtension = wellKnownExtensions[j]; + if (extensionId === wellKnownExtension.toLowerCase()) { + extensionId = wellKnownExtension; + break; + } + } + supportedKeys.set(extensionId.toLowerCase(), extensionId); } }); diff --git a/src/vs/platform/storage/test/node/storageService.test.ts b/src/vs/platform/storage/test/node/storageService.test.ts index 618892479eb..634967a79a7 100644 --- a/src/vs/platform/storage/test/node/storageService.test.ts +++ b/src/vs/platform/storage/test/node/storageService.test.ts @@ -4,8 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { strictEqual, ok, equal } from 'assert'; -import { StorageScope } from 'vs/platform/storage/common/storage'; -import { TestStorageService } from 'vs/workbench/test/workbenchTestServices'; +import { StorageScope, InMemoryStorageService } from 'vs/platform/storage/common/storage'; import { StorageService } from 'vs/platform/storage/node/storageService'; import { generateUuid } from 'vs/base/common/uuid'; import { join } from 'vs/base/common/path'; @@ -27,7 +26,7 @@ suite('StorageService', () => { }); function removeData(scope: StorageScope): void { - const storage = new TestStorageService(); + const storage = new InMemoryStorageService(); storage.store('Monaco.IDE.Core.Storage.Test.remove', 'foobar', scope); strictEqual('foobar', storage.get('Monaco.IDE.Core.Storage.Test.remove', scope, (undefined)!)); @@ -45,7 +44,7 @@ suite('StorageService', () => { }); function storeData(scope: StorageScope): void { - const storage = new TestStorageService(); + const storage = new InMemoryStorageService(); strictEqual(storage.get('Monaco.IDE.Core.Storage.Test.get', scope, 'foobar'), 'foobar'); strictEqual(storage.get('Monaco.IDE.Core.Storage.Test.get', scope, ''), ''); 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 92f60d3c088..1a15de0384b 100644 --- a/src/vs/platform/telemetry/test/electron-browser/commonProperties.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/commonProperties.test.ts @@ -7,7 +7,7 @@ import * as path from 'vs/base/common/path'; import * as os from 'os'; import * as fs from 'fs'; import { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/node/workbenchCommonProperties'; -import { getRandomTestPath } from 'vs/workbench/test/workbenchTestServices'; +import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { IStorageService, StorageScope, InMemoryStorageService } from 'vs/platform/storage/common/storage'; import { del } from 'vs/base/node/extfs'; import { mkdirp } from 'vs/base/node/pfs'; diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 9c26136e804..0b3362fffeb 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -310,6 +310,7 @@ export const editorFindRangeHighlightBorder = registerColor('editor.findRangeHig export const editorHoverHighlight = registerColor('editor.hoverHighlightBackground', { light: '#ADD6FF26', dark: '#264f7840', hc: '#ADD6FF26' }, nls.localize('hoverHighlight', 'Highlight below the word for which a hover is shown. The color must not be opaque so as not to hide underlying decorations.'), true); export const editorHoverBackground = registerColor('editorHoverWidget.background', { light: editorWidgetBackground, dark: editorWidgetBackground, hc: editorWidgetBackground }, nls.localize('hoverBackground', 'Background color of the editor hover.')); export const editorHoverBorder = registerColor('editorHoverWidget.border', { light: editorWidgetBorder, dark: editorWidgetBorder, hc: editorWidgetBorder }, nls.localize('hoverBorder', 'Border color of the editor hover.')); +export const editorHoverFooterBackground = registerColor('editorHoverWidget.footerBackground', { dark: Color.fromHex('#808080').transparent(0.2), light: Color.fromHex('#808080').transparent(0.2), hc: null }, nls.localize('hoverFotterground', "Background color of the editor hover footer.")); /** * Editor link colors 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 e5476a84dfd..670c1b5a8df 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts @@ -15,7 +15,7 @@ import { WorkspacesMainService, IStoredWorkspace } from 'vs/platform/workspaces/ import { WORKSPACE_EXTENSION, IWorkspaceIdentifier, IRawFileWorkspaceFolder, IWorkspaceFolderCreationData, IRawUriWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { NullLogService } from 'vs/platform/log/common/log'; import { URI } from 'vs/base/common/uri'; -import { getRandomTestPath } from 'vs/workbench/test/workbenchTestServices'; +import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { isWindows } from 'vs/base/common/platform'; import { normalizeDriveLetter } from 'vs/base/common/labels'; diff --git a/src/vs/workbench/api/electron-browser/mainThreadComments.ts b/src/vs/workbench/api/electron-browser/mainThreadComments.ts index b8b975d7188..5d7329f4b50 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadComments.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadComments.ts @@ -75,7 +75,7 @@ export class MainThreadDocumentCommentProvider implements modes.DocumentCommentP } - onDidChangeCommentThreads = null; + // onDidChangeCommentThreads = null; } @extHostNamedCustomer(MainContext.MainThreadComments) @@ -129,8 +129,10 @@ export class MainThreadComments extends Disposable implements MainThreadComments }); }); - this._openPanelListener.dispose(); - this._openPanelListener = null; + if (this._openPanelListener) { + this._openPanelListener.dispose(); + this._openPanelListener = null; + } } }); } diff --git a/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts b/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts index 7801fcbf337..dd73c36be3f 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts @@ -85,8 +85,8 @@ class DocumentAndEditorStateDelta { readonly addedDocuments: ITextModel[], readonly removedEditors: TextEditorSnapshot[], readonly addedEditors: TextEditorSnapshot[], - readonly oldActiveEditor: string | undefined, - readonly newActiveEditor: string | undefined, + readonly oldActiveEditor: string | null | undefined, + readonly newActiveEditor: string | null | undefined, ) { this.isEmpty = this.removedDocuments.length === 0 && this.addedDocuments.length === 0 @@ -131,7 +131,7 @@ class DocumentAndEditorState { constructor( readonly documents: Set, readonly textEditors: Map, - readonly activeEditor: string | undefined, + readonly activeEditor: string | null | undefined, ) { // } @@ -257,7 +257,7 @@ class MainThreadDocumentAndEditorStateComputer { // to match output panels or the active workbench editor with // one of editor we have just computed if (!activeEditor) { - let candidate: IEditor; + let candidate: IEditor | undefined; if (this._activeEditorOrder === ActiveEditorOrder.Editor) { candidate = this._getActiveEditorFromEditorPart() || this._getActiveEditorFromPanel(); } else { @@ -291,7 +291,7 @@ class MainThreadDocumentAndEditorStateComputer { } } - private _getActiveEditorFromEditorPart(): IEditor { + private _getActiveEditorFromEditorPart(): IEditor | undefined { let result = this._editorService.activeTextEditorWidget; if (isDiffEditor(result)) { result = result.getModifiedEditor(); diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts index 73dbc49ae4e..0be7720a10f 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts @@ -87,9 +87,10 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha private static _reviveWorkspaceSymbolDto(data: WorkspaceSymbolDto): search.IWorkspaceSymbol; private static _reviveWorkspaceSymbolDto(data: WorkspaceSymbolDto[]): search.IWorkspaceSymbol[]; - private static _reviveWorkspaceSymbolDto(data: WorkspaceSymbolDto | WorkspaceSymbolDto[]): search.IWorkspaceSymbol | search.IWorkspaceSymbol[] { + private static _reviveWorkspaceSymbolDto(data: undefined): undefined; + private static _reviveWorkspaceSymbolDto(data: WorkspaceSymbolDto | WorkspaceSymbolDto[] | undefined): search.IWorkspaceSymbol | search.IWorkspaceSymbol[] | undefined { if (!data) { - return data; + return data; } else if (Array.isArray(data)) { data.forEach(MainThreadLanguageFeatures._reviveWorkspaceSymbolDto); return data; @@ -99,7 +100,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha } } - private static _reviveCodeActionDto(data: CodeActionDto[]): modes.CodeAction[] { + private static _reviveCodeActionDto(data: CodeActionDto[] | undefined): modes.CodeAction[] { if (data) { data.forEach(code => reviveWorkspaceEditDto(code.edit)); } diff --git a/src/vs/workbench/api/electron-browser/mainThreadTask.ts b/src/vs/workbench/api/electron-browser/mainThreadTask.ts index 893d864fe10..cbbec5c214e 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTask.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTask.ts @@ -471,6 +471,7 @@ export class MainThreadTask implements MainThreadTaskShape { } public $unregisterTaskProvider(handle: number): Promise { + this._providers.get(handle).disposable.dispose(); this._providers.delete(handle); return Promise.resolve(undefined); } diff --git a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts index d1764ce52f4..e8b248cb19c 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts @@ -113,10 +113,11 @@ export class MainThreadWebviews implements MainThreadWebviewsShape { this._partService.getContainer(Parts.EDITOR_PART), { useSameOriginForRoot: true, - extensionLocation: URI.revive(extensionLocation) + extensionLocation: URI.revive(extensionLocation), + enableFindWidget: false, }, { - allowScripts: options.enableScripts + allowScripts: options.enableScripts, } ); diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index eec38cbcfa9..4687110352d 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -58,7 +58,7 @@ import * as extHostTypes from 'vs/workbench/api/node/extHostTypes'; import { ExtHostUrls } from 'vs/workbench/api/node/extHostUrls'; import { ExtHostWebviews } from 'vs/workbench/api/node/extHostWebview'; import { ExtHostWindow } from 'vs/workbench/api/node/extHostWindow'; -import { ExtHostWorkspace, ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { IExtensionDescription, throwProposedApiError, checkProposedApiEnabled, nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier'; import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry'; @@ -67,7 +67,7 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { originalFSPath } from 'vs/base/common/resources'; export interface IExtensionApiFactory { - (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, workspaceProvider: ExtHostWorkspaceProvider, configProvider: ExtHostConfigProvider): typeof vscode; + (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode; } function proposedApiFunction(extension: IExtensionDescription, fn: T): T { @@ -143,7 +143,7 @@ export function createApiFactory( // Register API-ish commands ExtHostApiCommands.register(extHostCommands); - return function (extension: IExtensionDescription, extensionRegistry: ExtensionDescriptionRegistry, workspaceProvider: ExtHostWorkspaceProvider, configProvider: ExtHostConfigProvider): typeof vscode { + return function (extension: IExtensionDescription, extensionRegistry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode { // Check document selectors for being overly generic. Technically this isn't a problem but // in practice many extensions say they support `fooLang` but need fs-access to do so. Those @@ -481,7 +481,7 @@ export function createApiFactory( createWebviewPanel(viewType: string, title: string, showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean }, options: vscode.WebviewPanelOptions & vscode.WebviewOptions): vscode.WebviewPanel { return extHostWebviews.createWebviewPanel(extension, viewType, title, showOptions, options); }, - createTerminal(nameOrOptions: vscode.TerminalOptions | string, shellPath?: string, shellArgs?: string[]): vscode.Terminal { + createTerminal(nameOrOptions?: vscode.TerminalOptions | string, shellPath?: string, shellArgs?: string[]): vscode.Terminal { if (typeof nameOrOptions === 'object') { return extHostTerminalService.createTerminalFromOptions(nameOrOptions); } @@ -506,7 +506,7 @@ export function createApiFactory( return extHostUrls.registerUriHandler(extension.identifier, handler); }, createQuickPick(): vscode.QuickPick { - return extHostQuickOpen.createQuickPick(extension.identifier, extension.enableProposedApi); + return extHostQuickOpen.createQuickPick(extension.identifier, !!extension.enableProposedApi); }, createInputBox(): vscode.InputBox { return extHostQuickOpen.createInputBox(extension.identifier); @@ -516,34 +516,34 @@ export function createApiFactory( // namespace: workspace const workspace: typeof vscode.workspace = { get rootPath() { - return workspaceProvider.getPath(); + return extHostWorkspace.getPath(); }, set rootPath(value) { throw errors.readonly(); }, getWorkspaceFolder(resource) { - return workspaceProvider.getWorkspaceFolder(resource); + return extHostWorkspace.getWorkspaceFolder(resource); }, get workspaceFolders() { - return workspaceProvider.getWorkspaceFolders(); + return extHostWorkspace.getWorkspaceFolders(); }, get name() { - return workspaceProvider.name; + return extHostWorkspace.name; }, set name(value) { throw errors.readonly(); }, updateWorkspaceFolders: (index, deleteCount, ...workspaceFoldersToAdd) => { - return workspaceProvider.updateWorkspaceFolders(extension, index, deleteCount || 0, ...workspaceFoldersToAdd); + return extHostWorkspace.updateWorkspaceFolders(extension, index, deleteCount || 0, ...workspaceFoldersToAdd); }, onDidChangeWorkspaceFolders: function (listener, thisArgs?, disposables?) { - return workspaceProvider.onDidChangeWorkspace(listener, thisArgs, disposables); + return extHostWorkspace.onDidChangeWorkspace(listener, thisArgs, disposables); }, asRelativePath: (pathOrUri, includeWorkspace) => { - return workspaceProvider.getRelativePath(pathOrUri, includeWorkspace); + return extHostWorkspace.getRelativePath(pathOrUri, includeWorkspace); }, findFiles: (include, exclude, maxResults?, token?) => { - return workspaceProvider.findFiles(typeConverters.GlobPattern.from(include), typeConverters.GlobPattern.from(exclude), maxResults, extension.identifier, token); + return extHostWorkspace.findFiles(typeConverters.GlobPattern.from(include), typeConverters.GlobPattern.from(exclude), maxResults, extension.identifier, token); }, findTextInFiles: (query: vscode.TextSearchQuery, optionsOrCallback, callbackOrToken?, token?: vscode.CancellationToken) => { let options: vscode.FindTextInFilesOptions; @@ -558,10 +558,10 @@ export function createApiFactory( token = callbackOrToken; } - return workspaceProvider.findTextInFiles(query, options || {}, callback, extension.identifier, token); + return extHostWorkspace.findTextInFiles(query, options || {}, callback, extension.identifier, token); }, saveAll: (includeUntitled?) => { - return workspaceProvider.saveAll(includeUntitled); + return extHostWorkspace.saveAll(includeUntitled); }, applyEdit(edit: vscode.WorkspaceEdit): Thenable { return extHostEditors.applyWorkspaceEdit(edit); @@ -591,8 +591,7 @@ export function createApiFactory( return uriPromise.then(uri => { return extHostDocuments.ensureDocumentData(uri).then(() => { - const data = extHostDocuments.getDocumentData(uri); - return data && data.document; + return extHostDocuments.getDocument(uri); }); }); }, @@ -876,11 +875,11 @@ class Extension implements vscode.Extension { } } -export function initializeExtensionApi(extensionService: ExtHostExtensionService, apiFactory: IExtensionApiFactory, extensionRegistry: ExtensionDescriptionRegistry, workspaceProvider: ExtHostWorkspaceProvider, configProvider: ExtHostConfigProvider): Promise { - return extensionService.getExtensionPathIndex().then(trie => defineAPI(apiFactory, trie, extensionRegistry, workspaceProvider, configProvider)); +export function initializeExtensionApi(extensionService: ExtHostExtensionService, apiFactory: IExtensionApiFactory, extensionRegistry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): Promise { + return extensionService.getExtensionPathIndex().then(trie => defineAPI(apiFactory, trie, extensionRegistry, configProvider)); } -function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchTree, extensionRegistry: ExtensionDescriptionRegistry, workspaceProvider: ExtHostWorkspaceProvider, configProvider: ExtHostConfigProvider): void { +function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchTree, extensionRegistry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): void { // each extension is meant to get its own api implementation const extApiImpl = new Map(); @@ -898,7 +897,7 @@ function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchT if (ext) { let apiImpl = extApiImpl.get(ExtensionIdentifier.toKey(ext.identifier)); if (!apiImpl) { - apiImpl = factory(ext, extensionRegistry, workspaceProvider, configProvider); + apiImpl = factory(ext, extensionRegistry, configProvider); extApiImpl.set(ExtensionIdentifier.toKey(ext.identifier), apiImpl); } return apiImpl; @@ -909,7 +908,7 @@ function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchT let extensionPathsPretty = ''; extensionPaths.forEach((value, index) => extensionPathsPretty += `\t${index} -> ${value.identifier.value}\n`); console.warn(`Could not identify extension for 'vscode' require call from ${parent.filename}. These are the extension path mappings: \n${extensionPathsPretty}`); - defaultApiImpl = factory(nullExtensionDescription, extensionRegistry, workspaceProvider, configProvider); + defaultApiImpl = factory(nullExtensionDescription, extensionRegistry, configProvider); } return defaultApiImpl; }; diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 6b6d00970a0..fa08e318edd 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -561,9 +561,9 @@ export interface MainThreadTaskShape extends IDisposable { export interface MainThreadExtensionServiceShape extends IDisposable { $localShowMessage(severity: Severity, msg: string): void; - $activateExtension(extensionId: ExtensionIdentifier, activationEvent: string): Promise; + $activateExtension(extensionId: ExtensionIdentifier, activationEvent: string | null): Promise; $onWillActivateExtension(extensionId: ExtensionIdentifier): void; - $onDidActivateExtension(extensionId: ExtensionIdentifier, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string): void; + $onDidActivateExtension(extensionId: ExtensionIdentifier, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string | null): void; $onExtensionActivationFailed(extensionId: ExtensionIdentifier): void; $onExtensionRuntimeError(extensionId: ExtensionIdentifier, error: SerializedError): void; $addMessage(extensionId: ExtensionIdentifier, severity: Severity, message: string): void; @@ -694,7 +694,7 @@ export interface ITextEditorAddData { options: IResolvedTextEditorConfiguration; selections: ISelection[]; visibleRanges: IRange[]; - editorPosition: EditorViewColumn; + editorPosition: EditorViewColumn | undefined; } export interface ITextEditorPositionData { [id: string]: EditorViewColumn; @@ -719,7 +719,7 @@ export interface IDocumentsAndEditorsDelta { addedDocuments?: IModelAddedData[]; removedEditors?: string[]; addedEditors?: ITextEditorAddData[]; - newActiveEditor?: string; + newActiveEditor?: string | null; } export interface ExtHostDocumentsAndEditorsShape { @@ -870,7 +870,7 @@ export interface WorkspaceEditDto { rejectReason?: string; } -export function reviveWorkspaceEditDto(data: WorkspaceEditDto): modes.WorkspaceEdit { +export function reviveWorkspaceEditDto(data: WorkspaceEditDto | undefined): modes.WorkspaceEdit { if (data && data.edits) { for (const edit of data.edits) { if (typeof (edit).resource === 'object') { @@ -911,7 +911,7 @@ export type CodeInsetDto = ObjectIdentifier & codeInset.ICodeInsetSymbol; export interface ExtHostLanguageFeaturesShape { $provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise; $provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise; - $resolveCodeLens(handle: number, resource: UriComponents, symbol: CodeLensDto, token: CancellationToken): Promise; + $resolveCodeLens(handle: number, resource: UriComponents, symbol: CodeLensDto, token: CancellationToken): Promise; $provideCodeInsets(handle: number, resource: UriComponents, token: CancellationToken): Promise; $resolveCodeInset(handle: number, resource: UriComponents, symbol: CodeInsetDto, token: CancellationToken): Promise; $provideDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; @@ -937,8 +937,8 @@ export interface ExtHostLanguageFeaturesShape { $provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise; $resolveDocumentLink(handle: number, link: LinkDto, token: CancellationToken): Promise; $provideDocumentColors(handle: number, resource: UriComponents, token: CancellationToken): Promise; - $provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise; - $provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext, token: CancellationToken): Promise; + $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; } diff --git a/src/vs/workbench/api/node/extHostComments.ts b/src/vs/workbench/api/node/extHostComments.ts index f1beb859241..38dc993f575 100644 --- a/src/vs/workbench/api/node/extHostComments.ts +++ b/src/vs/workbench/api/node/extHostComments.ts @@ -233,7 +233,7 @@ function convertFromCommentThread(commentThread: modes.CommentThread): vscode.Co } function convertFromComment(comment: modes.Comment): vscode.Comment { - let userIconPath: URI; + let userIconPath: URI | undefined; if (comment.userIconPath) { try { userIconPath = URI.parse(comment.userIconPath); diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index be43259afaf..6b4e53f964d 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -7,7 +7,7 @@ import { mixin, deepClone } from 'vs/base/common/objects'; import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import * as vscode from 'vscode'; -import { ExtHostWorkspace, ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostConfigurationShape, MainThreadConfigurationShape, IWorkspaceConfigurationChangeEventData, IConfigurationInitData } from './extHost.protocol'; import { ConfigurationTarget as ExtHostConfigurationTarget } from './extHostTypes'; import { IConfigurationData, ConfigurationTarget, IConfigurationModel } from 'vs/platform/configuration/common/configuration'; @@ -57,10 +57,8 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { } $initializeConfiguration(data: IConfigurationInitData): void { - this._extHostWorkspace.getWorkspaceProvider().then(workspaceProvider => { - this._actual = new ExtHostConfigProvider(this._proxy, workspaceProvider, data); - this._barrier.open(); - }); + this._actual = new ExtHostConfigProvider(this._proxy, this._extHostWorkspace, data); + this._barrier.open(); } $acceptConfigurationChanged(data: IConfigurationInitData, eventData: IWorkspaceConfigurationChangeEventData): void { @@ -72,11 +70,11 @@ export class ExtHostConfigProvider { private readonly _onDidChangeConfiguration = new Emitter(); private readonly _proxy: MainThreadConfigurationShape; - private readonly _extHostWorkspace: ExtHostWorkspaceProvider; + private readonly _extHostWorkspace: ExtHostWorkspace; private _configurationScopes: { [key: string]: ConfigurationScope }; private _configuration: Configuration; - constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspaceProvider, data: IConfigurationInitData) { + constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationInitData) { this._proxy = proxy; this._extHostWorkspace = extHostWorkspace; this._configuration = ExtHostConfigProvider.parse(data); diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 504c7b2ec17..1b44f2898d4 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -16,7 +16,7 @@ import { import * as vscode from 'vscode'; import { Disposable, Position, Location, SourceBreakpoint, FunctionBreakpoint, DebugAdapterServer, DebugAdapterExecutable } from 'vs/workbench/api/node/extHostTypes'; import { ExecutableDebugAdapter, SocketDebugAdapter, AbstractDebugAdapter } from 'vs/workbench/contrib/debug/node/debugAdapter'; -import { ExtHostWorkspace, ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; +import { IExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors'; import { ITerminalSettings, IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor } from 'vs/workbench/contrib/debug/common/debug'; @@ -82,7 +82,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { constructor(mainContext: IMainContext, - private _workspaceService: ExtHostWorkspace, + private _workspaceService: IExtHostWorkspaceProvider, private _extensionService: ExtHostExtensionService, private _editorsService: ExtHostDocumentsAndEditors, private _configurationService: ExtHostConfiguration, @@ -359,12 +359,12 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } public async $substituteVariables(folderUri: UriComponents | undefined, config: IConfig): Promise { - const [workspaceProvider, configProvider] = await Promise.all([this._workspaceService.getWorkspaceProvider(), this._configurationService.getConfigProvider()]); + const [workspaceFolders, configProvider] = await Promise.all([this._workspaceService.getWorkspaceFolders2(), this._configurationService.getConfigProvider()]); if (!this._variableResolver) { - this._variableResolver = new ExtHostVariableResolverService(workspaceProvider, this._editorsService, configProvider); + this._variableResolver = new ExtHostVariableResolverService(workspaceFolders, this._editorsService, configProvider); } - let ws: IWorkspaceFolder; - const folder = this.getFolder(folderUri, workspaceProvider); + let ws: IWorkspaceFolder | undefined; + const folder = await this.getFolder(folderUri); if (folder) { ws = { uri: folder.uri, @@ -379,10 +379,9 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } public async $startDASession(debugAdapterHandle: number, sessionDto: IDebugSessionDto): Promise { - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); const mythis = this; - const session = this.getSession(sessionDto, workspaceProvider); + const session = await this.getSession(sessionDto); return this.getAdapterDescriptor(this.getAdapterFactoryByType(session.type), session).then(x => { const adapter = this.convertToDto(x); @@ -547,7 +546,6 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } public async $provideDebugConfigurations(configProviderHandle: number, folderUri: UriComponents | undefined): Promise { - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); let provider = this.getConfigProviderByHandle(configProviderHandle); if (!provider) { return Promise.reject(new Error('no handler found')); @@ -555,11 +553,11 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { if (!provider.provideDebugConfigurations) { return Promise.reject(new Error('handler has no method provideDebugConfigurations')); } - return asPromise(() => provider.provideDebugConfigurations(this.getFolder(folderUri, workspaceProvider), CancellationToken.None)); + const folder = await this.getFolder(folderUri); + return asPromise(() => provider.provideDebugConfigurations(folder, CancellationToken.None)); } public async $resolveDebugConfiguration(configProviderHandle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration): Promise { - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); let provider = this.getConfigProviderByHandle(configProviderHandle); if (!provider) { return Promise.reject(new Error('no handler found')); @@ -567,12 +565,12 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { if (!provider.resolveDebugConfiguration) { return Promise.reject(new Error('handler has no method resolveDebugConfiguration')); } - return asPromise(() => provider.resolveDebugConfiguration(this.getFolder(folderUri, workspaceProvider), debugConfiguration, CancellationToken.None)); + const folder = await this.getFolder(folderUri); + return asPromise(() => provider.resolveDebugConfiguration(folder, debugConfiguration, CancellationToken.None)); } // TODO@AW legacy public async $legacyDebugAdapterExecutable(configProviderHandle: number, folderUri: UriComponents | undefined): Promise { - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); let provider = this.getConfigProviderByHandle(configProviderHandle); if (!provider) { return Promise.reject(new Error('no handler found')); @@ -580,26 +578,26 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { if (!provider.debugAdapterExecutable) { return Promise.reject(new Error('handler has no method debugAdapterExecutable')); } - return asPromise(() => provider.debugAdapterExecutable(this.getFolder(folderUri, workspaceProvider), CancellationToken.None)).then(x => this.convertToDto(x)); + const folder = await this.getFolder(folderUri); + return asPromise(() => provider.debugAdapterExecutable(folder, CancellationToken.None)).then(x => this.convertToDto(x)); } public async $provideDebugAdapter(adapterProviderHandle: number, sessionDto: IDebugSessionDto): Promise { - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); let adapterProvider = this.getAdapterProviderByHandle(adapterProviderHandle); if (!adapterProvider) { return Promise.reject(new Error('no handler found')); } - return this.getAdapterDescriptor(adapterProvider, this.getSession(sessionDto, workspaceProvider)).then(x => this.convertToDto(x)); + const session = await this.getSession(sessionDto); + return this.getAdapterDescriptor(adapterProvider, session).then(x => this.convertToDto(x)); } public async $acceptDebugSessionStarted(sessionDto: IDebugSessionDto): Promise { - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); - this._onDidStartDebugSession.fire(this.getSession(sessionDto, workspaceProvider)); + const session = await this.getSession(sessionDto); + this._onDidStartDebugSession.fire(session); } public async $acceptDebugSessionTerminated(sessionDto: IDebugSessionDto): Promise { - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); - const session = this.getSession(sessionDto, workspaceProvider); + const session = await this.getSession(sessionDto); if (session) { this._onDidTerminateDebugSession.fire(session); this._debugSessions.delete(session.id); @@ -607,15 +605,14 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } public async $acceptDebugSessionActiveChanged(sessionDto: IDebugSessionDto | undefined): Promise { - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); - this._activeDebugSession = sessionDto ? this.getSession(sessionDto, workspaceProvider) : undefined; + this._activeDebugSession = sessionDto ? await this.getSession(sessionDto) : undefined; this._onDidChangeActiveDebugSession.fire(this._activeDebugSession); } public async $acceptDebugSessionCustomEvent(sessionDto: IDebugSessionDto, event: any): Promise { - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); + const session = await this.getSession(sessionDto); const ee: vscode.DebugSessionCustomEvent = { - session: this.getSession(sessionDto, workspaceProvider), + session: session, event: event.event, body: event.body }; @@ -780,12 +777,13 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } } - private getSession(dto: IDebugSessionDto, workspaceProvider: ExtHostWorkspaceProvider): ExtHostDebugSession { + private async getSession(dto: IDebugSessionDto): Promise { if (dto) { if (typeof dto === 'string') { return this._debugSessions.get(dto); } else { - const debugSession = new ExtHostDebugSession(this._debugServiceProxy, dto.id, dto.type, dto.name, this.getFolder(dto.folderUri, workspaceProvider), dto.configuration); + const folder = await this.getFolder(dto.folderUri); + const debugSession = new ExtHostDebugSession(this._debugServiceProxy, dto.id, dto.type, dto.name, folder, dto.configuration); this._debugSessions.set(debugSession.id, debugSession); return debugSession; } @@ -793,10 +791,10 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { return undefined; } - private getFolder(_folderUri: UriComponents | undefined, workspaceProvider: ExtHostWorkspaceProvider): vscode.WorkspaceFolder | undefined { + private async getFolder(_folderUri: UriComponents | undefined): Promise { if (_folderUri) { const folderURI = URI.revive(_folderUri); - return workspaceProvider.resolveWorkspaceFolder(folderURI); + return await this._workspaceService.resolveWorkspaceFolder2(folderURI); } return undefined; } @@ -857,10 +855,9 @@ export class ExtHostDebugConsole implements vscode.DebugConsole { export class ExtHostVariableResolverService extends AbstractVariableResolverService { - constructor(workspaceService: ExtHostWorkspaceProvider, editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider) { + constructor(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider) { super({ getFolderUri: (folderName: string): URI => { - const folders = workspaceService.getWorkspaceFolders(); const found = folders.filter(f => f.name === folderName); if (found && found.length > 0) { return found[0].uri; @@ -868,7 +865,7 @@ export class ExtHostVariableResolverService extends AbstractVariableResolverServ return undefined; }, getWorkspaceFolderCount: (): number => { - return workspaceService.getWorkspaceFolders().length; + return folders.length; }, getConfigurationValue: (folderUri: URI, section: string) => { return configurationService.getConfiguration(undefined, folderUri).get(section); diff --git a/src/vs/workbench/api/node/extHostDiagnostics.ts b/src/vs/workbench/api/node/extHostDiagnostics.ts index 229ea037c4d..791de4d587d 100644 --- a/src/vs/workbench/api/node/extHostDiagnostics.ts +++ b/src/vs/workbench/api/node/extHostDiagnostics.ts @@ -120,7 +120,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection { // compute change and send to main side const entries: [URI, IMarkerData[]][] = []; for (let uri of toSync) { - let marker: IMarkerData[]; + let marker: IMarkerData[] | undefined; let diagnostics = this._data.get(uri.toString()); if (diagnostics) { diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index ce45a06e521..2f0c9249f94 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -18,7 +18,7 @@ import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionMemento, IExtensionModule, HostExtension } from 'vs/workbench/api/node/extHostExtensionActivator'; import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService'; import { ExtHostStorage } from 'vs/workbench/api/node/extHostStorage'; -import { ExtHostWorkspace, ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry'; import { connectProxyResolver } from 'vs/workbench/services/extensions/node/proxyResolver'; @@ -166,7 +166,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { private readonly _storage: ExtHostStorage; private readonly _storagePath: ExtensionStoragePath; private readonly _activator: ExtensionsActivator; - private _extensionPathIndex: Promise>; + private _extensionPathIndex: Promise> | null; private readonly _extensionApiFactory: IExtensionApiFactory; private readonly _resolvers: { [authorityPrefix: string]: vscode.RemoteAuthorityResolver; }; @@ -222,7 +222,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { await this._mainThreadExtensionsProxy.$activateExtension(extensionId, activationEvent); return new HostExtension(); } - const extensionDescription = this._registry.getExtensionDescription(extensionId); + const extensionDescription = this._registry.getExtensionDescription(extensionId)!; return this._activateExtension(extensionDescription, reason); } }); @@ -245,10 +245,10 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { private async _initialize(): Promise { try { const configProvider = await this._extHostConfiguration.getConfigProvider(); - const workspaceProvider = await this._extHostWorkspace.getWorkspaceProvider(); - await initializeExtensionApi(this, this._extensionApiFactory, this._registry, workspaceProvider, configProvider); + await this._extHostWorkspace.waitForInitializeCall(); + await initializeExtensionApi(this, this._extensionApiFactory, this._registry, configProvider); // Do this when extension service exists, but extensions are not being activated yet. - await connectProxyResolver(workspaceProvider, configProvider, this, this._extHostLogService, this._mainThreadTelemetryProxy); + await connectProxyResolver(this._extHostWorkspace, configProvider, this, this._extHostLogService, this._mainThreadTelemetryProxy); this._barrier.open(); } catch (err) { errors.onUnexpectedError(err); @@ -302,7 +302,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { return this._barrier.wait().then(_ => this._registry); } - public getExtensionExports(extensionId: ExtensionIdentifier): IExtensionAPI { + public getExtensionExports(extensionId: ExtensionIdentifier): IExtensionAPI | null | undefined { if (this._barrier.isOpen()) { return this._activator.getActivatedExtension(extensionId).exports; } else { @@ -490,12 +490,12 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { // -- eager activation // Handle "eager" activation extensions - private _handleEagerExtensions(workspaceProvider: ExtHostWorkspaceProvider): Promise { + private _handleEagerExtensions(): Promise { this._activateByEvent('*', true).then(undefined, (err) => { console.error(err); }); - return this._handleWorkspaceContainsEagerExtensions(workspaceProvider.workspace); + return this._handleWorkspaceContainsEagerExtensions(this._extHostWorkspace.workspace); } private _handleWorkspaceContainsEagerExtensions(workspace: IWorkspace | undefined): Promise { @@ -624,7 +624,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { // Execute the runner if it follows our spec if (testRunner && typeof testRunner.run === 'function') { return new Promise((c, e) => { - testRunner!.run(this._initData.environment.extensionTestsPath, (error, failures) => { + testRunner!.run(this._initData.environment.extensionTestsPath!, (error, failures) => { if (error) { e(error.toString()); } else { @@ -658,8 +658,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { this._started = true; return this._barrier.wait() - .then(() => this._extHostWorkspace.getWorkspaceProvider()) - .then(workspaceProvider => this._handleEagerExtensions(workspaceProvider)) + .then(() => this._handleEagerExtensions()) .then(() => this._handleExtensionTests()) .then(() => { this._extHostLogService.info(`eager extensions activated`); @@ -671,7 +670,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { public registerRemoteAuthorityResolver(authorityPrefix: string, resolver: vscode.RemoteAuthorityResolver): vscode.Disposable { this._resolvers[authorityPrefix] = resolver; return toDisposable(() => { - this._resolvers[authorityPrefix] = null; + delete this._resolvers[authorityPrefix]; }); } diff --git a/src/vs/workbench/api/node/extHostFileSystem.ts b/src/vs/workbench/api/node/extHostFileSystem.ts index cb8b9b548f2..3c6b5db39f2 100644 --- a/src/vs/workbench/api/node/extHostFileSystem.ts +++ b/src/vs/workbench/api/node/extHostFileSystem.ts @@ -13,7 +13,7 @@ import * as typeConverter from 'vs/workbench/api/node/extHostTypeConverters'; import { ExtHostLanguageFeatures } from 'vs/workbench/api/node/extHostLanguageFeatures'; import { Schemas } from 'vs/base/common/network'; import { ResourceLabelFormatter } from 'vs/platform/label/common/label'; -import { State, StateMachine, LinkComputer } from 'vs/editor/common/modes/linkComputer'; +import { State, StateMachine, LinkComputer, Edge } from 'vs/editor/common/modes/linkComputer'; import { commonPrefixLength } from 'vs/base/common/strings'; import { CharCode } from 'vs/base/common/charCode'; @@ -41,8 +41,8 @@ class FsLinkProvider { // sort and compute common prefix with previous scheme // then build state transitions based on the data const schemes = this._schemes.sort(); - const edges = []; - let prevScheme: string; + const edges: Edge[] = []; + let prevScheme: string | undefined; let prevState: State; let nextState = State.LastKnownState; for (const scheme of schemes) { @@ -178,7 +178,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { // dropping events for wrong scheme continue; } - let newType: files.FileChangeType; + let newType: files.FileChangeType | undefined; switch (type) { case FileChangeType.Changed: newType = files.FileChangeType.UPDATED; diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index fc0a93e2f08..b4b5d85a067 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -19,7 +19,7 @@ import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesSh 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'; -import { isFalsyOrEmpty, isNonEmptyArray } from 'vs/base/common/arrays'; +import { isFalsyOrEmpty, isNonEmptyArray, coalesce } from 'vs/base/common/arrays'; import { isObject } from 'vs/base/common/types'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; @@ -155,8 +155,8 @@ class CodeInsetAdapter { private readonly _provider: vscode.CodeInsetProvider ) { } - provideCodeInsets(resource: URI, token: CancellationToken): Promise { - const doc = this._documents.getDocumentData(resource).document; + provideCodeInsets(resource: URI, token: CancellationToken): Promise { + const doc = this._documents.getDocument(resource); return asPromise(() => this._provider.provideCodeInsets(doc, token)).then(insets => { if (Array.isArray(insets)) { return insets.map(inset => { @@ -572,10 +572,10 @@ class RenameAdapter { const doc = this._documents.getDocument(resource); let pos = typeConvert.Position.to(position); - return asPromise(() => this._provider.prepareRename(doc, pos, token)).then(rangeOrLocation => { + return asPromise(() => this._provider.prepareRename!(doc, pos, token)).then(rangeOrLocation => { let range: vscode.Range | undefined; - let text: string; + let text: string | undefined; if (Range.isRange(rangeOrLocation)) { range = rangeOrLocation; text = doc.getText(rangeOrLocation); @@ -924,11 +924,11 @@ class SelectionRangeAdapter { ) { } provideSelectionRanges(resource: URI, pos: IPosition[], token: CancellationToken): Promise { - const { document } = this._documents.getDocumentData(resource); + const document = this._documents.getDocument(resource); const positions = pos.map(typeConvert.Position.to); return asPromise(() => this._provider.provideSelectionRanges(document, positions, token)).then(allProviderRanges => { - if (isFalsyOrEmpty(allProviderRanges)) { + if (!isNonEmptyArray(allProviderRanges)) { return []; } if (allProviderRanges.length !== positions.length) { @@ -1006,12 +1006,12 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { this._webviewProxy = mainContext.getProxy(MainContext.MainThreadWebviews); } - private _transformDocumentSelector(selector: vscode.DocumentSelector): ISerializedDocumentFilter[] { + private _transformDocumentSelector(selector: vscode.DocumentSelector): Array { if (Array.isArray(selector)) { - return selector.map(sel => this._doTransformDocumentSelector(sel)); + return coalesce(selector.map(sel => this._doTransformDocumentSelector(sel))); } - return [this._doTransformDocumentSelector(selector)]; + return coalesce([this._doTransformDocumentSelector(selector)]); } private _doTransformDocumentSelector(selector: string | vscode.DocumentFilter): ISerializedDocumentFilter | undefined { @@ -1035,7 +1035,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return undefined; } - private _transformScheme(scheme: string): string { + private _transformScheme(scheme: string | undefined): string | undefined { if (this._schemeTransformer && typeof scheme === 'string') { return this._schemeTransformer.transformOutgoing(scheme); } @@ -1126,7 +1126,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource), token)); } - $resolveCodeLens(handle: number, resource: UriComponents, symbol: modes.ICodeLensSymbol, token: CancellationToken): Promise { + $resolveCodeLens(handle: number, resource: UriComponents, symbol: modes.ICodeLensSymbol, token: CancellationToken): Promise { return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(URI.revive(resource), symbol, token)); } @@ -1382,7 +1382,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { 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: IRawColorInfo, token: CancellationToken): Promise { return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(URI.revive(resource), colorInfo, token)); } @@ -1392,7 +1392,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideFoldingRanges(handle: number, resource: UriComponents, context: vscode.FoldingContext, token: CancellationToken): Promise { + $provideFoldingRanges(handle: number, resource: UriComponents, context: vscode.FoldingContext, token: CancellationToken): Promise { return this._withAdapter(handle, FoldingProviderAdapter, adapter => adapter.provideFoldingRanges(URI.revive(resource), context, token)); } diff --git a/src/vs/workbench/api/node/extHostQuickOpen.ts b/src/vs/workbench/api/node/extHostQuickOpen.ts index c2a196eb685..7b8dd2432ee 100644 --- a/src/vs/workbench/api/node/extHostQuickOpen.ts +++ b/src/vs/workbench/api/node/extHostQuickOpen.ts @@ -8,7 +8,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter } from 'vs/base/common/event'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; -import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; +import { IExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; import { InputBox, InputBoxOptions, QuickInput, QuickInputButton, QuickPick, QuickPickItem, QuickPickOptions, WorkspaceFolder, WorkspaceFolderPickOptions } from 'vscode'; import { ExtHostQuickOpenShape, IMainContext, MainContext, MainThreadQuickOpenShape, TransferQuickPickItems, TransferQuickInput, TransferQuickInputButton } from './extHost.protocol'; import { URI } from 'vs/base/common/uri'; @@ -21,7 +21,7 @@ export type Item = string | QuickPickItem; export class ExtHostQuickOpen implements ExtHostQuickOpenShape { private _proxy: MainThreadQuickOpenShape; - private _workspace: ExtHostWorkspace; + private _workspace: IExtHostWorkspaceProvider; private _commands: ExtHostCommands; private _onDidSelectItem: (handle: number) => void; @@ -31,7 +31,7 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape { private _instances = 0; - constructor(mainContext: IMainContext, workspace: ExtHostWorkspace, commands: ExtHostCommands) { + constructor(mainContext: IMainContext, workspace: IExtHostWorkspaceProvider, commands: ExtHostCommands) { this._proxy = mainContext.getProxy(MainContext.MainThreadQuickOpen); this._workspace = workspace; this._commands = commands; @@ -159,12 +159,12 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape { // ---- workspace folder picker showWorkspaceFolderPick(options?: WorkspaceFolderPickOptions, token = CancellationToken.None): Promise { - return this._commands.executeCommand('_workbench.pickWorkspaceFolder', [options]).then((selectedFolder: WorkspaceFolder) => { + return this._commands.executeCommand('_workbench.pickWorkspaceFolder', [options]).then(async (selectedFolder: WorkspaceFolder) => { if (!selectedFolder) { return undefined; } - - return this._workspace.getWorkspaceProvider().then(workspaceProvider => workspaceProvider.getWorkspaceFolders().filter(folder => folder.uri.toString() === selectedFolder.uri.toString())[0]); + const workspaceFolders = await this._workspace.getWorkspaceFolders2(); + return workspaceFolders.filter(folder => folder.uri.toString() === selectedFolder.uri.toString())[0]; }); } diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index 1e7656efab5..92b45f4a2b2 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -16,7 +16,7 @@ import { IExtensionDescription } from 'vs/workbench/services/extensions/common/e import { MainContext, MainThreadTaskShape, ExtHostTaskShape, IMainContext } from 'vs/workbench/api/node/extHost.protocol'; import * as types from 'vs/workbench/api/node/extHostTypes'; -import { ExtHostWorkspace, ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspace, IExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; import * as vscode from 'vscode'; import { TaskDefinitionDTO, TaskExecutionDTO, TaskPresentationOptionsDTO, @@ -168,7 +168,7 @@ namespace CustomExecutionDTO { namespace TaskHandleDTO { export function from(value: types.Task): TaskHandleDTO { - let folder: UriComponents; + let folder: UriComponents | undefined; if (value.scope !== undefined && typeof value.scope !== 'number') { folder = value.scope.uri; } @@ -199,7 +199,7 @@ namespace TaskDTO { if (value === undefined || value === null) { return undefined; } - let execution: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO; + let execution: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | undefined; if (value.execution instanceof types.ProcessExecution) { execution = ProcessExecutionDTO.from(value.execution); } else if (value.execution instanceof types.ShellExecution) { @@ -243,24 +243,24 @@ namespace TaskDTO { }; return result; } - export function to(value: TaskDTO, workspace: ExtHostWorkspaceProvider): types.Task { + export async function to(value: TaskDTO, workspace: IExtHostWorkspaceProvider): Promise { if (value === undefined || value === null) { return undefined; } - let execution: types.ShellExecution | types.ProcessExecution; + let execution: types.ShellExecution | types.ProcessExecution | undefined; if (ProcessExecutionDTO.is(value.execution)) { execution = ProcessExecutionDTO.to(value.execution); } else if (ShellExecutionDTO.is(value.execution)) { execution = ShellExecutionDTO.to(value.execution); } let definition: vscode.TaskDefinition = TaskDefinitionDTO.to(value.definition); - let scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder; + let scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder | undefined; if (value.source) { if (value.source.scope !== undefined) { if (typeof value.source.scope === 'number') { scope = value.source.scope; } else { - scope = workspace.resolveWorkspaceFolder(URI.revive(value.source.scope)); + scope = await workspace.resolveWorkspaceFolder2(URI.revive(value.source.scope)); } } else { scope = types.TaskScope.Workspace; @@ -320,8 +320,8 @@ class TaskExecutionImpl implements vscode.TaskExecution { } namespace TaskExecutionDTO { - export function to(value: TaskExecutionDTO, tasks: ExtHostTask, workspaceProvider: ExtHostWorkspaceProvider): vscode.TaskExecution { - return new TaskExecutionImpl(tasks, value.id, TaskDTO.to(value.task, workspaceProvider)); + export async function to(value: TaskExecutionDTO, tasks: ExtHostTask, workspaceProvider: IExtHostWorkspaceProvider): Promise { + return new TaskExecutionImpl(tasks, value.id, await TaskDTO.to(value.task, workspaceProvider)); } export function from(value: vscode.TaskExecution): TaskExecutionDTO { return { @@ -417,7 +417,7 @@ class CustomExecutionData implements IDisposable { export class ExtHostTask implements ExtHostTaskShape { private _proxy: MainThreadTaskShape; - private _workspaceService: ExtHostWorkspace; + private _workspaceProvider: IExtHostWorkspaceProvider; private _editorService: ExtHostDocumentsAndEditors; private _configurationService: ExtHostConfiguration; private _terminalService: ExtHostTerminalService; @@ -440,7 +440,7 @@ export class ExtHostTask implements ExtHostTaskShape { configurationService: ExtHostConfiguration, extHostTerminalService: ExtHostTerminalService) { this._proxy = mainContext.getProxy(MainContext.MainThreadTask); - this._workspaceService = workspaceService; + this._workspaceProvider = workspaceService; this._editorService = editorService; this._configurationService = configurationService; this._terminalService = extHostTerminalService; @@ -471,9 +471,8 @@ export class ExtHostTask implements ExtHostTaskShape { public fetchTasks(filter?: vscode.TaskFilter): Promise { return this._proxy.$fetchTasks(TaskFilterDTO.from(filter)).then(async (values) => { let result: vscode.Task[] = []; - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); for (let value of values) { - let task = TaskDTO.to(value, workspaceProvider); + let task = await TaskDTO.to(value, this._workspaceProvider); if (task) { result.push(task); } @@ -483,17 +482,16 @@ export class ExtHostTask implements ExtHostTaskShape { } public async executeTask(extension: IExtensionDescription, task: vscode.Task): Promise { - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); let tTask = (task as types.Task); // We have a preserved ID. So the task didn't change. if (tTask._id !== undefined) { - return this._proxy.$executeTask(TaskHandleDTO.from(tTask)).then(value => this.getTaskExecution(value, workspaceProvider, task)); + return this._proxy.$executeTask(TaskHandleDTO.from(tTask)).then(value => this.getTaskExecution(value, task)); } else { let dto = TaskDTO.from(task, extension); if (dto === undefined) { return Promise.reject(new Error('Task is not valid')); } - return this._proxy.$executeTask(dto).then(value => this.getTaskExecution(value, workspaceProvider, task)); + return this._proxy.$executeTask(dto).then(value => this.getTaskExecution(value, task)); } } @@ -534,9 +532,8 @@ export class ExtHostTask implements ExtHostTaskShape { extensionCallback.startCallback(terminalId); } - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); this._onDidExecuteTask.fire({ - execution: this.getTaskExecution(execution, workspaceProvider) + execution: await this.getTaskExecution(execution) }); } @@ -545,8 +542,7 @@ export class ExtHostTask implements ExtHostTaskShape { } public async $OnDidEndTask(execution: TaskExecutionDTO): Promise { - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); - const _execution = this.getTaskExecution(execution, workspaceProvider); + const _execution = await this.getTaskExecution(execution); this._taskExecutions.delete(execution.id); this.customExecutionComplete(execution); this._onDidTerminateTask.fire({ @@ -559,8 +555,7 @@ export class ExtHostTask implements ExtHostTaskShape { } public async $onDidStartTaskProcess(value: TaskProcessStartedDTO): Promise { - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); - const execution = this.getTaskExecution(value.id, workspaceProvider); + const execution = await this.getTaskExecution(value.id); if (execution) { this._onDidTaskProcessStarted.fire({ execution: execution, @@ -574,8 +569,7 @@ export class ExtHostTask implements ExtHostTaskShape { } public async $onDidEndTaskProcess(value: TaskProcessEndedDTO): Promise { - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); - const execution = this.getTaskExecution(value.id, workspaceProvider); + const execution = await this.getTaskExecution(value.id); if (execution) { this._onDidTaskProcessEnded.fire({ execution: execution, @@ -644,14 +638,14 @@ export class ExtHostTask implements ExtHostTaskShape { public async $resolveVariables(uriComponents: UriComponents, toResolve: { process?: { name: string; cwd?: string; path?: string }, variables: string[] }): Promise<{ process?: string, variables: { [key: string]: string; } }> { const configProvider = await this._configurationService.getConfigProvider(); - const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); let uri: URI = URI.revive(uriComponents); let result = { process: undefined as string, variables: Object.create(null) }; - let workspaceFolder = workspaceProvider.resolveWorkspaceFolder(uri); - let resolver = new ExtHostVariableResolverService(workspaceProvider, this._editorService, configProvider); + let workspaceFolder = await this._workspaceProvider.resolveWorkspaceFolder2(uri); + const workspaceFolders = await this._workspaceProvider.getWorkspaceFolders2(); + let resolver = new ExtHostVariableResolverService(workspaceFolders, this._editorService, configProvider); let ws: IWorkspaceFolder = { uri: workspaceFolder.uri, name: workspaceFolder.name, @@ -684,7 +678,7 @@ export class ExtHostTask implements ExtHostTaskShape { return this._handleCounter++; } - private getTaskExecution(execution: TaskExecutionDTO | string, workspaceProvider: ExtHostWorkspaceProvider, task?: vscode.Task): TaskExecutionImpl { + private async getTaskExecution(execution: TaskExecutionDTO | string, task?: vscode.Task): Promise { if (typeof execution === 'string') { return this._taskExecutions.get(execution); } @@ -693,7 +687,7 @@ export class ExtHostTask implements ExtHostTaskShape { if (result) { return result; } - result = new TaskExecutionImpl(this, execution.id, task ? task : TaskDTO.to(execution.task, workspaceProvider)); + result = new TaskExecutionImpl(this, execution.id, task ? task : await TaskDTO.to(execution.task, this._workspaceProvider)); this._taskExecutions.set(execution.id, result); return result; } diff --git a/src/vs/workbench/api/node/extHostTextEditors.ts b/src/vs/workbench/api/node/extHostTextEditors.ts index 2ebad811a31..3b316662afb 100644 --- a/src/vs/workbench/api/node/extHostTextEditors.ts +++ b/src/vs/workbench/api/node/extHostTextEditors.ts @@ -53,8 +53,8 @@ export class ExtHostEditors implements ExtHostEditorsShape { showTextDocument(document: vscode.TextDocument, column: vscode.ViewColumn, preserveFocus: boolean): Promise; showTextDocument(document: vscode.TextDocument, options: { column: vscode.ViewColumn, preserveFocus: boolean, pinned: boolean }): Promise; - showTextDocument(document: vscode.TextDocument, columnOrOptions: vscode.ViewColumn | vscode.TextDocumentShowOptions, preserveFocus?: boolean): Promise; - showTextDocument(document: vscode.TextDocument, columnOrOptions: vscode.ViewColumn | vscode.TextDocumentShowOptions, preserveFocus?: boolean): Promise { + showTextDocument(document: vscode.TextDocument, columnOrOptions: vscode.ViewColumn | vscode.TextDocumentShowOptions | undefined, preserveFocus?: boolean): Promise; + showTextDocument(document: vscode.TextDocument, columnOrOptions: vscode.ViewColumn | vscode.TextDocumentShowOptions | undefined, preserveFocus?: boolean): Promise { let options: ITextDocumentShowOptions; if (typeof columnOrOptions === 'number') { options = { diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index 4cd66f5e7c6..6de98c9c63c 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -22,10 +22,17 @@ import { Range, RelativePattern } from 'vs/workbench/api/node/extHostTypes'; import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder'; import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import * as vscode from 'vscode'; -import { ExtHostWorkspaceShape, IWorkspaceData, MainThreadMessageServiceShape, MainThreadWorkspaceShape, IMainContext, MainContext } from './extHost.protocol'; +import { ExtHostWorkspaceShape, IWorkspaceData, MainThreadMessageServiceShape, MainThreadWorkspaceShape, IMainContext, MainContext, IStaticWorkspaceData } from './extHost.protocol'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { Barrier } from 'vs/base/common/async'; +export interface IExtHostWorkspaceProvider { + getWorkspaceFolder2(uri: vscode.Uri, resolveParent?: boolean): Promise; + resolveWorkspaceFolder2(uri: vscode.Uri): Promise; + getWorkspaceFolders2(): Promise; + resolveProxy(url: string): Promise; +} + function isFolderEqual(folderA: URI, folderB: URI): boolean { return isEqual(folderA, folderB, !isLinux); } @@ -109,7 +116,7 @@ class ExtHostWorkspaceImpl extends Workspace { private readonly _workspaceFolders: vscode.WorkspaceFolder[] = []; private readonly _structure = TernarySearchTree.forPaths(); - private constructor(id: string, private _name: string, folders: vscode.WorkspaceFolder[]) { + constructor(id: string, private _name: string, folders: vscode.WorkspaceFolder[]) { super(id, folders.map(f => new WorkspaceFolder(f))); // setup the workspace folder data structure @@ -140,51 +147,14 @@ class ExtHostWorkspaceImpl extends Workspace { } } -export class ExtHostWorkspace implements ExtHostWorkspaceShape { +export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspaceProvider { + + private readonly _onDidChangeWorkspace = new Emitter(); + readonly onDidChangeWorkspace: Event = this._onDidChangeWorkspace.event; - private readonly _mainContext: IMainContext; private readonly _logService: ILogService; private readonly _requestIdProvider: Counter; private readonly _barrier: Barrier; - private _actual: ExtHostWorkspaceProvider | null; - - constructor( - mainContext: IMainContext, - logService: ILogService, - requestIdProvider: Counter - ) { - this._mainContext = mainContext; - this._logService = logService; - this._requestIdProvider = requestIdProvider; - this._barrier = new Barrier(); - this._actual = null; - } - - public getWorkspaceProvider(): Promise { - return this._barrier.wait().then(_ => this._actual!); - } - - $initializeWorkspace(data: IWorkspaceData): void { - this._actual = new ExtHostWorkspaceProvider(this._mainContext, data, this._logService, this._requestIdProvider); - this._barrier.open(); - } - - $acceptWorkspaceData(workspace: IWorkspaceData): void { - if (this._actual) { - this._actual.$acceptWorkspaceData(workspace); - } - } - - $handleTextSearchResult(result: IRawFileMatch2, requestId: number): void { - if (this._actual) { - this._actual.$handleTextSearchResult(result, requestId); - } - } - -} -export class ExtHostWorkspaceProvider { - - private readonly _onDidChangeWorkspace = new Emitter(); private _confirmedWorkspace?: ExtHostWorkspaceImpl; private _unconfirmedWorkspace?: ExtHostWorkspaceImpl; @@ -192,19 +162,30 @@ export class ExtHostWorkspaceProvider { private readonly _proxy: MainThreadWorkspaceShape; private readonly _messageService: MainThreadMessageServiceShape; - readonly onDidChangeWorkspace: Event = this._onDidChangeWorkspace.event; - private readonly _activeSearchCallbacks: ((match: IRawFileMatch2) => any)[] = []; constructor( mainContext: IMainContext, - data: IWorkspaceData | null, - private _logService: ILogService, - private _requestIdProvider: Counter + logService: ILogService, + requestIdProvider: Counter, + data?: IStaticWorkspaceData ) { + this._logService = logService; + this._requestIdProvider = requestIdProvider; + this._barrier = new Barrier(); + this._proxy = mainContext.getProxy(MainContext.MainThreadWorkspace); this._messageService = mainContext.getProxy(MainContext.MainThreadMessageService); - this._confirmedWorkspace = ExtHostWorkspaceImpl.toExtHostWorkspace(data).workspace || undefined; + this._confirmedWorkspace = data ? new ExtHostWorkspaceImpl(data.id, data.name, []) : undefined; + } + + $initializeWorkspace(data: IWorkspaceData): void { + this.$acceptWorkspaceData(data); + this._barrier.open(); + } + + waitForInitializeCall(): Promise { + return this._barrier.wait(); } // --- workspace --- @@ -228,6 +209,14 @@ export class ExtHostWorkspaceProvider { return this._actualWorkspace.workspaceFolders.slice(0); } + async getWorkspaceFolders2(): Promise { + await this._barrier.wait(); + if (!this._actualWorkspace) { + return undefined; + } + return this._actualWorkspace.workspaceFolders.slice(0); + } + updateWorkspaceFolders(extension: IExtensionDescription, index: number, deleteCount: number, ...workspaceFoldersToAdd: { uri: vscode.Uri, name?: string }[]): boolean { const validatedDistinctWorkspaceFoldersToAdd: { uri: vscode.Uri, name?: string }[] = []; if (Array.isArray(workspaceFoldersToAdd)) { @@ -299,6 +288,14 @@ export class ExtHostWorkspaceProvider { return this._actualWorkspace.getWorkspaceFolder(uri, resolveParent); } + async getWorkspaceFolder2(uri: vscode.Uri, resolveParent?: boolean): Promise { + await this._barrier.wait(); + if (!this._actualWorkspace) { + return undefined; + } + return this._actualWorkspace.getWorkspaceFolder(uri, resolveParent); + } + resolveWorkspaceFolder(uri: vscode.Uri): vscode.WorkspaceFolder | undefined { if (!this._actualWorkspace) { return undefined; @@ -306,6 +303,14 @@ export class ExtHostWorkspaceProvider { return this._actualWorkspace.resolveWorkspaceFolder(uri); } + async resolveWorkspaceFolder2(uri: vscode.Uri): Promise { + await this._barrier.wait(); + if (!this._actualWorkspace) { + return undefined; + } + return this._actualWorkspace.resolveWorkspaceFolder(uri); + } + getPath(): string | undefined { // this is legacy from the days before having diff --git a/src/vs/workbench/browser/actions/listCommands.ts b/src/vs/workbench/browser/actions/listCommands.ts index d47aa860d21..9585039149a 100644 --- a/src/vs/workbench/browser/actions/listCommands.ts +++ b/src/vs/workbench/browser/actions/listCommands.ts @@ -752,7 +752,8 @@ CommandsRegistry.registerCommand({ // List if (focused instanceof List || focused instanceof PagedList) { - // TODO@joao + const list = focused; + list.toggleKeyboardNavigation(); } // ObjectTree diff --git a/src/vs/workbench/browser/media/style.css b/src/vs/workbench/browser/media/style.css index 8848f027b9d..0bd743e7af5 100644 --- a/src/vs/workbench/browser/media/style.css +++ b/src/vs/workbench/browser/media/style.css @@ -5,27 +5,27 @@ /* Font Families (with CJK support) */ -.monaco-workbench.mac { font-family: -apple-system, BlinkMacSystemFont, sans-serif; } -.monaco-workbench.mac:lang(zh-Hans) { font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", sans-serif; } -.monaco-workbench.mac:lang(zh-Hant) { font-family: -apple-system, BlinkMacSystemFont, "PingFang TC", sans-serif; } -.monaco-workbench.mac:lang(ja) { font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic Pro", sans-serif; } -.monaco-workbench.mac:lang(ko) { font-family: -apple-system, BlinkMacSystemFont, "Nanum Gothic", "Apple SD Gothic Neo", "AppleGothic", sans-serif; } +.mac { font-family: -apple-system, BlinkMacSystemFont, sans-serif; } +.mac:lang(zh-Hans) { font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", sans-serif; } +.mac:lang(zh-Hant) { font-family: -apple-system, BlinkMacSystemFont, "PingFang TC", sans-serif; } +.mac:lang(ja) { font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic Pro", sans-serif; } +.mac:lang(ko) { font-family: -apple-system, BlinkMacSystemFont, "Nanum Gothic", "Apple SD Gothic Neo", "AppleGothic", sans-serif; } -.monaco-workbench.windows { font-family: "Segoe WPC", "Segoe UI", sans-serif; } -.monaco-workbench.windows:lang(zh-Hans) { font-family: "Segoe WPC", "Segoe UI", "Microsoft YaHei", sans-serif; } -.monaco-workbench.windows:lang(zh-Hant) { font-family: "Segoe WPC", "Segoe UI", "Microsoft Jhenghei", sans-serif; } -.monaco-workbench.windows:lang(ja) { font-family: "Segoe WPC", "Segoe UI", "Meiryo", sans-serif; } -.monaco-workbench.windows:lang(ko) { font-family: "Segoe WPC", "Segoe UI", "Malgun Gothic", "Dotom", sans-serif; } +.windows { font-family: "Segoe WPC", "Segoe UI", sans-serif; } +.windows:lang(zh-Hans) { font-family: "Segoe WPC", "Segoe UI", "Microsoft YaHei", sans-serif; } +.windows:lang(zh-Hant) { font-family: "Segoe WPC", "Segoe UI", "Microsoft Jhenghei", sans-serif; } +.windows:lang(ja) { font-family: "Segoe WPC", "Segoe UI", "Meiryo", sans-serif; } +.windows:lang(ko) { font-family: "Segoe WPC", "Segoe UI", "Malgun Gothic", "Dotom", sans-serif; } -.monaco-workbench.linux { font-family: "Ubuntu", "Droid Sans", sans-serif; } -.monaco-workbench.linux:lang(zh-Hans) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; } -.monaco-workbench.linux:lang(zh-Hant) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans", sans-serif; } -.monaco-workbench.linux:lang(ja) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", sans-serif; } -.monaco-workbench.linux:lang(ko) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; } +.linux { font-family: "Ubuntu", "Droid Sans", sans-serif; } +.linux:lang(zh-Hans) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; } +.linux:lang(zh-Hant) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans", sans-serif; } +.linux:lang(ja) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", sans-serif; } +.linux:lang(ko) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; } -.monaco-workbench.mac { --monaco-monospace-font: Monaco, Menlo, Inconsolata, "Courier New", monospace; } -.monaco-workbench.windows { --monaco-monospace-font: Consolas, Inconsolata, "Courier New", monospace; } -.monaco-workbench.linux { --monaco-monospace-font: "Droid Sans Mono", Inconsolata, "Courier New", monospace, "Droid Sans Fallback"; } +.mac { --monaco-monospace-font: Monaco, Menlo, Inconsolata, "Courier New", monospace; } +.windows { --monaco-monospace-font: Consolas, Inconsolata, "Courier New", monospace; } +.linux { --monaco-monospace-font: "Droid Sans Mono", Inconsolata, "Courier New", monospace, "Droid Sans Fallback"; } /* Global Styles */ @@ -41,20 +41,6 @@ body { @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } -.monaco-font-aliasing-antialiased { - -webkit-font-smoothing: antialiased; -} - -.monaco-font-aliasing-none { - -webkit-font-smoothing: none; -} - -@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { - .monaco-font-aliasing-auto { - -webkit-font-smoothing: antialiased; - } -} - .monaco-workbench { font-size: 13px; line-height: 1.4em; @@ -105,6 +91,20 @@ body { cursor: pointer; } +.monaco-workbench .monaco-font-aliasing-antialiased { + -webkit-font-smoothing: antialiased; +} + +.monaco-workbench .monaco-font-aliasing-none { + -webkit-font-smoothing: none; +} + +@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { + .monaco-workbench .monaco-font-aliasing-auto { + -webkit-font-smoothing: antialiased; + } +} + .monaco-workbench .context-view { -webkit-app-region: no-drag; } diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 947618b4b32..d9369905d02 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -452,7 +452,7 @@ export class BreadcrumbsControl { MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: 'breadcrumbs.toggle', - title: { value: localize('cmd.toggle', "Toggle Breadcrumbs"), original: 'Toggle Breadcrumbs' }, + title: { value: localize('cmd.toggle', "Toggle Breadcrumbs"), original: 'View: Toggle Breadcrumbs' }, category: localize('cmd.category', "View") } }); diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts index 8d18052b55a..0ffe5b0f277 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts @@ -140,7 +140,7 @@ export abstract class BreadcrumbsPicker { protected _layout(info: ILayoutInfo = this._layoutInfo): void { const headerHeight = 2 * info.arrowSize; - const treeHeight = Math.min(info.maxHeight - headerHeight, this._tree.visibleNodeCount * 22); + const treeHeight = Math.min(info.maxHeight - headerHeight, this._tree.contentHeight); const totalHeight = treeHeight + headerHeight; this._domNode.style.height = `${totalHeight}px`; @@ -407,7 +407,7 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker { const tree = this._tree as WorkbenchAsyncDataTree; return tree.setInput(input).then(() => { - let focusElement: IWorkspaceFolder | IFileStat; + let focusElement: IWorkspaceFolder | IFileStat | undefined; for (const { element } of tree.getNode().children) { if (IWorkspaceFolder.isIWorkspaceFolder(element) && isEqual(element.uri, uri)) { focusElement = element; diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 403dae5c587..0a3d443d567 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -17,7 +17,7 @@ import { attachProgressBarStyler } from 'vs/platform/theme/common/styler'; import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { editorBackground, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { Themable, EDITOR_GROUP_HEADER_TABS_BORDER, EDITOR_GROUP_HEADER_TABS_BACKGROUND, EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND, EDITOR_GROUP_EMPTY_BACKGROUND, EDITOR_GROUP_FOCUSED_EMPTY_BORDER } from 'vs/workbench/common/theme'; -import { IMoveEditorOptions, ICopyEditorOptions, ICloseEditorsFilter, IGroupChangeEvent, GroupChangeKind, EditorsOrder, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { IMoveEditorOptions, ICopyEditorOptions, ICloseEditorsFilter, IGroupChangeEvent, GroupChangeKind, EditorsOrder, GroupsOrder, ICloseEditorOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; import { TabsTitleControl } from 'vs/workbench/browser/parts/editor/tabsTitleControl'; import { EditorControl } from 'vs/workbench/browser/parts/editor/editorControl'; import { IProgressService } from 'vs/platform/progress/common/progress'; @@ -518,7 +518,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { private handleDisposedEditors(editors: EditorInput[]): void { // Split between visible and hidden editors - let activeEditor: EditorInput; + let activeEditor: EditorInput | undefined; const inactiveEditors: EditorInput[] = []; editors.forEach(editor => { if (this._group.isActive(editor)) { @@ -958,7 +958,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { //#region closeEditor() - closeEditor(editor: EditorInput = this.activeEditor): Promise { + closeEditor(editor: EditorInput = this.activeEditor, options?: ICloseEditorOptions): Promise { if (!editor) { return Promise.resolve(); } @@ -970,11 +970,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } // Do close - this.doCloseEditor(editor); + this.doCloseEditor(editor, options && options.preserveFocus ? false : undefined); }); } - private doCloseEditor(editor: EditorInput, focusNext = this.accessor.activeGroup === this, fromError?: boolean): void { + private doCloseEditor(editor: EditorInput, focusNext = (this.accessor.activeGroup === this), fromError?: boolean): void { // Closing the active editor of the group is a bit more work if (this._group.isActive(editor)) { @@ -990,7 +990,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { this.titleAreaControl.closeEditor(editor); } - private doCloseActiveEditor(focusNext = this.accessor.activeGroup === this, fromError?: boolean): void { + private doCloseActiveEditor(focusNext = (this.accessor.activeGroup === this), fromError?: boolean): void { const editorToClose = this.activeEditor; const restoreFocus = this.shouldRestoreFocus(this.element); @@ -1149,7 +1149,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { //#region closeEditors() - closeEditors(args: EditorInput[] | ICloseEditorsFilter): Promise { + closeEditors(args: EditorInput[] | ICloseEditorsFilter, options?: ICloseEditorOptions): Promise { if (this.isEmpty()) { return Promise.resolve(); } @@ -1163,7 +1163,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } // Do close - this.doCloseEditors(editors); + this.doCloseEditors(editors, options); }); } @@ -1197,7 +1197,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { return editorsToClose; } - private doCloseEditors(editors: EditorInput[]): void { + private doCloseEditors(editors: EditorInput[], options?: ICloseEditorOptions): void { // Close all inactive editors first let closeActiveEditor = false; @@ -1211,7 +1211,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Close active editor last if contained in editors list to close if (closeActiveEditor) { - this.doCloseActiveEditor(); + this.doCloseActiveEditor(options && options.preserveFocus ? false : undefined); } // Forward to title control @@ -1270,7 +1270,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { replaceEditors(editors: EditorReplacement[]): Promise { // Extract active vs. inactive replacements - let activeReplacement: EditorReplacement; + let activeReplacement: EditorReplacement | undefined; const inactiveReplacements: EditorReplacement[] = []; editors.forEach(({ editor, replacement, options }) => { if (editor.isDirty()) { diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index 951d1b81b3c..de05b9a3e91 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -993,8 +993,8 @@ export class TabsTitleControl extends TitleControl { const visibleContainerWidth = this.tabsContainer.offsetWidth; const totalContainerWidth = this.tabsContainer.scrollWidth; - let activeTabPosX: number; - let activeTabWidth: number; + let activeTabPosX: number | undefined; + let activeTabWidth: number | undefined; if (!this.blockRevealActiveTab) { activeTabPosX = activeTab.offsetLeft; diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts index 2e9ef883959..946df2f2d4c 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -317,6 +317,8 @@ class QuickPick extends QuickInput implements IQuickPi private _canSelectMany = false; private _matchOnDescription = false; private _matchOnDetail = false; + private _matchOnLabel = true; + private _autoFocusOnList = true; private _activeItems: T[] = []; private activeItemsUpdated = false; private activeItemsToConfirm: T[] | null = []; @@ -399,6 +401,24 @@ class QuickPick extends QuickInput implements IQuickPi this.update(); } + get matchOnLabel() { + return this._matchOnLabel; + } + + set matchOnLabel(matchOnLabel: boolean) { + this._matchOnLabel = matchOnLabel; + this.update(); + } + + get autoFocusOnList() { + return this._autoFocusOnList; + } + + set autoFocusOnList(autoFocusOnList: boolean) { + this._autoFocusOnList = autoFocusOnList; + this.update(); + } + get activeItems() { return this._activeItems; } @@ -429,6 +449,14 @@ class QuickPick extends QuickInput implements IQuickPi onDidTriggerItemButton = this.onDidTriggerItemButtonEmitter.event; + private trySelectFirst() { + if (this.autoFocusOnList) { + if (!this.ui.isScreenReaderOptimized() && !this.canSelectMany) { + this.ui.list.focus('First'); + } + } + } + show() { if (!this.visible) { this.visibleDisposables.push( @@ -438,11 +466,14 @@ class QuickPick extends QuickInput implements IQuickPi } this._value = value; this.ui.list.filter(this.ui.inputBox.value); - if (!this.ui.isScreenReaderOptimized() && !this.canSelectMany) { - this.ui.list.focus('First'); - } + this.trySelectFirst(); this.onDidChangeValueEmitter.fire(value); }), + this.ui.inputBox.onMouseDown(event => { + if (!this.autoFocusOnList) { + this.ui.list.clearFocus(); + } + }), this.ui.inputBox.onKeyDown(event => { switch (event.keyCode) { case KeyCode.DownArrow: @@ -599,15 +630,13 @@ class QuickPick extends QuickInput implements IQuickPi this.ui.checkAll.checked = this.ui.list.getAllVisibleChecked(); this.ui.visibleCount.setCount(this.ui.list.getVisibleCount()); this.ui.count.setCount(this.ui.list.getCheckedCount()); - if (!this.ui.isScreenReaderOptimized() && !this.canSelectMany) { - this.ui.list.focus('First'); - } + this.trySelectFirst(); } if (this.ui.container.classList.contains('show-checkboxes') !== !!this.canSelectMany) { if (this.canSelectMany) { this.ui.list.clearFocus(); - } else if (!this.ui.isScreenReaderOptimized()) { - this.ui.list.focus('First'); + } else { + this.trySelectFirst(); } } if (this.activeItemsUpdated) { @@ -632,6 +661,7 @@ class QuickPick extends QuickInput implements IQuickPi } this.ui.list.matchOnDescription = this.matchOnDescription; this.ui.list.matchOnDetail = this.matchOnDetail; + this.ui.list.matchOnLabel = this.matchOnLabel; this.ui.setComboboxAccessibility(true); this.ui.inputBox.setAttribute('aria-label', QuickPick.INPUT_BOX_ARIA_LABEL); this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, checkAll: true, inputBox: true, visibleCount: true, count: true, ok: true, list: true } : { title: !!this.title || !!this.step, inputBox: true, visibleCount: true, list: true }); @@ -1119,6 +1149,8 @@ export class QuickInputService extends Component implements IQuickInputService { input.ignoreFocusOut = !!options.ignoreFocusLost; input.matchOnDescription = !!options.matchOnDescription; input.matchOnDetail = !!options.matchOnDetail; + input.matchOnLabel = (options.matchOnLabel === undefined) || options.matchOnLabel; // default to true + input.autoFocusOnList = (options.autoFocusOnList === undefined) || options.autoFocusOnList; // default to true input.quickNavigate = options.quickNavigate; input.contextKey = options.contextKey; input.busy = true; @@ -1236,6 +1268,7 @@ export class QuickInputService extends Component implements IQuickInputService { this.ui.list.setElements([]); this.ui.list.matchOnDescription = false; this.ui.list.matchOnDetail = false; + this.ui.list.matchOnLabel = true; this.ui.ignoreFocusOut = false; this.setComboboxAccessibility(false); this.ui.inputBox.removeAttribute('aria-label'); diff --git a/src/vs/workbench/browser/parts/quickinput/quickInputBox.ts b/src/vs/workbench/browser/parts/quickinput/quickInputBox.ts index 08ede924c14..701e5723113 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInputBox.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInputBox.ts @@ -11,6 +11,7 @@ import { ITheme } from 'vs/platform/theme/common/themeService'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import Severity from 'vs/base/common/severity'; +import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; const $ = dom.$; @@ -34,6 +35,12 @@ export class QuickInputBox { }); } + onMouseDown = (handler: (event: StandardMouseEvent) => void): IDisposable => { + return dom.addDisposableListener(this.inputBox.inputElement, dom.EventType.MOUSE_DOWN, (e: MouseEvent) => { + handler(new StandardMouseEvent(e)); + }); + } + onDidChange = (handler: (event: string) => void): IDisposable => { return this.inputBox.onDidChange(handler); } diff --git a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts index f24bb0bcc09..b02f59ad490 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts @@ -220,6 +220,7 @@ export class QuickInputList { private elementsToIndexes = new Map(); matchOnDescription = false; matchOnDetail = false; + matchOnLabel = true; private _onChangedAllVisibleChecked = new Emitter(); onChangedAllVisibleChecked: Event = this._onChangedAllVisibleChecked.event; private _onChangedCheckedCount = new Emitter(); @@ -397,6 +398,9 @@ export class QuickInputList { this.list.setFocus(items .filter(item => this.elementsToIndexes.has(item)) .map(item => this.elementsToIndexes.get(item)!)); + if (items.length > 0) { + this.list.reveal(this.list.getFocus()[0]); + } } getActiveDescendant() { @@ -483,9 +487,9 @@ export class QuickInputList { } // Filter by value (since we support octicons, use octicon aware fuzzy matching) - else { + else if (this.matchOnLabel || this.matchOnDescription || this.matchOnDetail) { this.elements.forEach(element => { - const labelHighlights = matchesFuzzyOcticonAware(query, parseOcticons(element.saneLabel)) || undefined; + const labelHighlights = this.matchOnLabel ? matchesFuzzyOcticonAware(query, parseOcticons(element.saneLabel)) || undefined : undefined; const descriptionHighlights = this.matchOnDescription ? matchesFuzzyOcticonAware(query, parseOcticons(element.saneDescription || '')) || undefined : undefined; const detailHighlights = this.matchOnDetail ? matchesFuzzyOcticonAware(query, parseOcticons(element.saneDetail || '')) || undefined : undefined; diff --git a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css index 8c31b3a23ec..c3f5d7944f1 100644 --- a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css +++ b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css @@ -33,25 +33,24 @@ border-right: 5px solid transparent; } -.monaco-workbench .part.statusbar > .statusbar-item.left > :first-child { - margin-right: 5px; +.monaco-workbench .part.statusbar > .statusbar-item.left > :first-child, +.monaco-workbench .part.statusbar > .statusbar-item.right > :first-child +{ + margin-right: 3px; + margin-left: 3px; } .monaco-workbench .part.statusbar > .statusbar-item.right { float: right; } -.monaco-workbench .part.statusbar > .statusbar-item.right > :first-child { - margin-left: 5px; -} - /* adding padding to the most left status bar item */ .monaco-workbench .part.statusbar > .statusbar-item.left:first-child, .monaco-workbench .part.statusbar > .statusbar-item.right + .statusbar-item.left { - padding-left: 10px; + padding-left: 7px; } /* adding padding to the most right status bar item */ .monaco-workbench .part.statusbar > .statusbar-item.right:first-child { - padding-right: 10px; + padding-right: 7px; } .monaco-workbench .part.statusbar > .statusbar-item a { diff --git a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts index 12cdbfd61d1..dee2551e3f2 100644 --- a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -477,6 +477,7 @@ export class MenubarControl extends Disposable { if (!isMacintosh) { const updateAction = this.getUpdateAction(); if (updateAction) { + updateAction.label = mnemonicMenuLabel(updateAction.label); target.push(updateAction); target.push(new Separator()); } diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index 1da57592349..655cb9b27cf 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -196,7 +196,7 @@ export class CollapseAction extends Action { // Collapse All action for the new tree export class CollapseAction2 extends Action { - constructor(tree: AsyncDataTree | AbstractTree, enabled: boolean, clazz: string) { + constructor(tree: AsyncDataTree | AbstractTree, enabled: boolean, clazz?: string) { super('workbench.action.collapse', nls.localize('collapse', "Collapse All"), clazz, enabled, () => { tree.collapseAll(); return Promise.resolve(undefined); diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index 12f78547309..1eb763e0023 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -8,280 +8,283 @@ import * as nls from 'vs/nls'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { isMacintosh } from 'vs/base/common/platform'; -const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); +// Configuration +(function registerConfiguration(): void { + const registry = Registry.as(ConfigurationExtensions.Configuration); -// Configuration: Workbench -configurationRegistry.registerConfiguration({ - 'id': 'workbench', - 'order': 7, - 'title': nls.localize('workbenchConfigurationTitle', "Workbench"), - 'type': 'object', - 'properties': { - 'workbench.editor.showTabs': { - 'type': 'boolean', - 'description': nls.localize('showEditorTabs', "Controls whether opened editors should show in tabs or not."), - 'default': true - }, - 'workbench.editor.highlightModifiedTabs': { - 'type': 'boolean', - 'description': nls.localize('highlightModifiedTabs', "Controls whether a top border is drawn on modified (dirty) editor tabs or not."), - 'default': false - }, - 'workbench.editor.labelFormat': { - 'type': 'string', - 'enum': ['default', 'short', 'medium', 'long'], - 'enumDescriptions': [ - nls.localize('workbench.editor.labelFormat.default', "Show the name of the file. When tabs are enabled and two files have the same name in one group the distinguishing sections of each file's path are added. When tabs are disabled, the path relative to the workspace folder is shown if the editor is active."), - nls.localize('workbench.editor.labelFormat.short', "Show the name of the file followed by its directory name."), - nls.localize('workbench.editor.labelFormat.medium', "Show the name of the file followed by its path relative to the workspace folder."), - nls.localize('workbench.editor.labelFormat.long', "Show the name of the file followed by its absolute path.") - ], - 'default': 'default', - 'description': nls.localize({ - comment: ['This is the description for a setting. Values surrounded by parenthesis are not to be translated.'], - key: 'tabDescription' - }, "Controls the format of the label for an editor."), - }, - 'workbench.editor.tabCloseButton': { - 'type': 'string', - 'enum': ['left', 'right', 'off'], - 'default': 'right', - 'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorTabCloseButton' }, "Controls the position of the editor's tabs close buttons, or disables them when set to 'off'.") - }, - 'workbench.editor.tabSizing': { - 'type': 'string', - 'enum': ['fit', 'shrink'], - 'default': 'fit', - 'enumDescriptions': [ - nls.localize('workbench.editor.tabSizing.fit', "Always keep tabs large enough to show the full editor label."), - nls.localize('workbench.editor.tabSizing.shrink', "Allow tabs to get smaller when the available space is not enough to show all tabs at once.") - ], - 'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'tabSizing' }, "Controls the sizing of editor tabs.") - }, - 'workbench.editor.focusRecentEditorAfterClose': { - 'type': 'boolean', - 'description': nls.localize('focusRecentEditorAfterClose', "Controls whether tabs are closed in most recently used order or from left to right."), - 'default': true - }, - 'workbench.editor.showIcons': { - 'type': 'boolean', - 'description': nls.localize('showIcons', "Controls whether opened editors should show with an icon or not. This requires an icon theme to be enabled as well."), - 'default': true - }, - 'workbench.editor.enablePreview': { - 'type': 'boolean', - 'description': nls.localize('enablePreview', "Controls whether opened editors show as preview. Preview editors are reused until they are pinned (e.g. via double click or editing) and show up with an italic font style."), - 'default': true - }, - 'workbench.editor.enablePreviewFromQuickOpen': { - 'type': 'boolean', - 'description': nls.localize('enablePreviewFromQuickOpen', "Controls whether opened editors from Quick Open show as preview. Preview editors are reused until they are pinned (e.g. via double click or editing)."), - 'default': true - }, - 'workbench.editor.closeOnFileDelete': { - 'type': 'boolean', - 'description': nls.localize('closeOnFileDelete', "Controls whether editors showing a file that was opened during the session should close automatically when getting deleted or renamed by some other process. Disabling this will keep the editor open on such an event. Note that deleting from within the application will always close the editor and that dirty files will never close to preserve your data."), - 'default': false - }, - 'workbench.editor.openPositioning': { - 'type': 'string', - 'enum': ['left', 'right', 'first', 'last'], - 'default': 'right', - 'markdownDescription': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorOpenPositioning' }, "Controls where editors open. Select `left` or `right` to open editors to the left or right of the currently active one. Select `first` or `last` to open editors independently from the currently active one.") - }, - 'workbench.editor.openSideBySideDirection': { - 'type': 'string', - 'enum': ['right', 'down'], - 'default': 'right', - 'markdownDescription': nls.localize('sideBySideDirection', "Controls the default direction of editors that are opened side by side (e.g. from the explorer). By default, editors will open on the right hand side of the currently active one. If changed to `down`, the editors will open below the currently active one.") - }, - 'workbench.editor.closeEmptyGroups': { - 'type': 'boolean', - 'description': nls.localize('closeEmptyGroups', "Controls the behavior of empty editor groups when the last tab in the group is closed. When enabled, empty groups will automatically close. When disabled, empty groups will remain part of the grid."), - 'default': true - }, - 'workbench.editor.revealIfOpen': { - 'type': 'boolean', - 'description': nls.localize('revealIfOpen', "Controls whether an editor is revealed in any of the visible groups if opened. If disabled, an editor will prefer to open in the currently active editor group. If enabled, an already opened editor will be revealed instead of opened again in the currently active editor group. Note that there are some cases where this setting is ignored, e.g. when forcing an editor to open in a specific group or to the side of the currently active group."), - 'default': false - }, - 'workbench.editor.swipeToNavigate': { - 'type': 'boolean', - 'description': nls.localize('swipeToNavigate', "Navigate between open files using three-finger swipe horizontally."), - 'default': false, - 'included': isMacintosh - }, - 'workbench.editor.restoreViewState': { - 'type': 'boolean', - 'description': nls.localize('restoreViewState', "Restores the last view state (e.g. scroll position) when re-opening files after they have been closed."), - 'default': true, - }, - 'workbench.editor.centeredLayoutAutoResize': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('centeredLayoutAutoResize', "Controls if the centered layout should automatically resize to maximum width when more than one group is open. Once only one group is open it will resize back to the original centered width.") - }, - 'workbench.commandPalette.history': { - 'type': 'number', - 'description': nls.localize('commandHistory', "Controls the number of recently used commands to keep in history for the command palette. Set to 0 to disable command history."), - 'default': 50 - }, - 'workbench.commandPalette.preserveInput': { - 'type': 'boolean', - 'description': nls.localize('preserveInput', "Controls whether the last typed input to the command palette should be restored when opening it the next time."), - 'default': false - }, - 'workbench.quickOpen.closeOnFocusLost': { - 'type': 'boolean', - 'description': nls.localize('closeOnFocusLost', "Controls whether Quick Open should close automatically once it loses focus."), - 'default': true - }, - 'workbench.quickOpen.preserveInput': { - 'type': 'boolean', - 'description': nls.localize('workbench.quickOpen.preserveInput', "Controls whether the last typed input to Quick Open should be restored when opening it the next time."), - 'default': false - }, - 'workbench.settings.openDefaultSettings': { - 'type': 'boolean', - 'description': nls.localize('openDefaultSettings', "Controls whether opening settings also opens an editor showing all default settings."), - 'default': false - }, - 'workbench.settings.useSplitJSON': { - 'type': 'boolean', - 'markdownDescription': nls.localize('useSplitJSON', "Controls whether to use the split JSON editor when editing settings as JSON."), - 'default': false - }, - 'workbench.settings.openDefaultKeybindings': { - 'type': 'boolean', - 'description': nls.localize('openDefaultKeybindings', "Controls whether opening keybinding settings also opens an editor showing all default keybindings."), - 'default': false - }, - 'workbench.sideBar.location': { - 'type': 'string', - 'enum': ['left', 'right'], - 'default': 'left', - 'description': nls.localize('sideBarLocation', "Controls the location of the sidebar. It can either show on the left or right of the workbench.") - }, - 'workbench.panel.defaultLocation': { - 'type': 'string', - 'enum': ['bottom', 'right'], - 'default': 'bottom', - 'description': nls.localize('panelDefaultLocation', "Controls the default location of the panel (terminal, debug console, output, problems). It can either show at the bottom or on the right of the workbench.") - }, - 'workbench.statusBar.visible': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('statusBarVisibility', "Controls the visibility of the status bar at the bottom of the workbench.") - }, - 'workbench.activityBar.visible': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('activityBarVisibility', "Controls the visibility of the activity bar in the workbench.") - }, - 'workbench.view.alwaysShowHeaderActions': { - 'type': 'boolean', - 'default': false, - 'description': nls.localize('viewVisibility', "Controls the visibility of view header actions. View header actions may either be always visible, or only visible when that view is focused or hovered over.") - }, - 'workbench.fontAliasing': { - 'type': 'string', - 'enum': ['default', 'antialiased', 'none', 'auto'], - 'default': 'default', - 'description': - nls.localize('fontAliasing', "Controls font aliasing method in the workbench."), - 'enumDescriptions': [ - nls.localize('workbench.fontAliasing.default', "Sub-pixel font smoothing. On most non-retina displays this will give the sharpest text."), - nls.localize('workbench.fontAliasing.antialiased', "Smooth the font on the level of the pixel, as opposed to the subpixel. Can make the font appear lighter overall."), - nls.localize('workbench.fontAliasing.none', "Disables font smoothing. Text will show with jagged sharp edges."), - nls.localize('workbench.fontAliasing.auto', "Applies `default` or `antialiased` automatically based on the DPI of displays.") - ], - 'included': isMacintosh - }, - 'workbench.settings.enableNaturalLanguageSearch': { - 'type': 'boolean', - 'description': nls.localize('enableNaturalLanguageSettingsSearch', "Controls whether to enable the natural language search mode for settings. The natural language search is provided by a Microsoft online service."), - 'default': true, - 'scope': ConfigurationScope.WINDOW, - 'tags': ['usesOnlineServices'] - }, - 'workbench.settings.settingsSearchTocBehavior': { - 'type': 'string', - 'enum': ['hide', 'filter'], - 'enumDescriptions': [ - nls.localize('settingsSearchTocBehavior.hide', "Hide the Table of Contents while searching."), - nls.localize('settingsSearchTocBehavior.filter', "Filter the Table of Contents to just categories that have matching settings. Clicking a category will filter the results to that category."), - ], - 'description': nls.localize('settingsSearchTocBehavior', "Controls the behavior of the settings editor Table of Contents while searching."), - 'default': 'filter', - 'scope': ConfigurationScope.WINDOW - }, - 'workbench.settings.editor': { - 'type': 'string', - 'enum': ['ui', 'json'], - 'enumDescriptions': [ - nls.localize('settings.editor.ui', "Use the settings UI editor."), - nls.localize('settings.editor.json', "Use the JSON file editor."), - ], - 'description': nls.localize('settings.editor.desc', "Determines which settings editor to use by default."), - 'default': 'ui', - 'scope': ConfigurationScope.WINDOW - }, - 'workbench.enableExperiments': { - 'type': 'boolean', - 'description': nls.localize('workbench.enableExperiments', "Fetches experiments to run from a Microsoft online service."), - 'default': true, - 'tags': ['usesOnlineServices'] - }, - 'workbench.useExperimentalGridLayout': { - 'type': 'boolean', - 'description': nls.localize('workbench.useExperimentalGridLayout', "Enables the grid layout for the workbench. This setting may enable additional layout options for workbench components."), - 'default': false, - 'scope': ConfigurationScope.APPLICATION + // Workbench + registry.registerConfiguration({ + 'id': 'workbench', + 'order': 7, + 'title': nls.localize('workbenchConfigurationTitle', "Workbench"), + 'type': 'object', + 'properties': { + 'workbench.editor.showTabs': { + 'type': 'boolean', + 'description': nls.localize('showEditorTabs', "Controls whether opened editors should show in tabs or not."), + 'default': true + }, + 'workbench.editor.highlightModifiedTabs': { + 'type': 'boolean', + 'description': nls.localize('highlightModifiedTabs', "Controls whether a top border is drawn on modified (dirty) editor tabs or not."), + 'default': false + }, + 'workbench.editor.labelFormat': { + 'type': 'string', + 'enum': ['default', 'short', 'medium', 'long'], + 'enumDescriptions': [ + nls.localize('workbench.editor.labelFormat.default', "Show the name of the file. When tabs are enabled and two files have the same name in one group the distinguishing sections of each file's path are added. When tabs are disabled, the path relative to the workspace folder is shown if the editor is active."), + nls.localize('workbench.editor.labelFormat.short', "Show the name of the file followed by its directory name."), + nls.localize('workbench.editor.labelFormat.medium', "Show the name of the file followed by its path relative to the workspace folder."), + nls.localize('workbench.editor.labelFormat.long', "Show the name of the file followed by its absolute path.") + ], + 'default': 'default', + 'description': nls.localize({ + comment: ['This is the description for a setting. Values surrounded by parenthesis are not to be translated.'], + key: 'tabDescription' + }, "Controls the format of the label for an editor."), + }, + 'workbench.editor.tabCloseButton': { + 'type': 'string', + 'enum': ['left', 'right', 'off'], + 'default': 'right', + 'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorTabCloseButton' }, "Controls the position of the editor's tabs close buttons, or disables them when set to 'off'.") + }, + 'workbench.editor.tabSizing': { + 'type': 'string', + 'enum': ['fit', 'shrink'], + 'default': 'fit', + 'enumDescriptions': [ + nls.localize('workbench.editor.tabSizing.fit', "Always keep tabs large enough to show the full editor label."), + nls.localize('workbench.editor.tabSizing.shrink', "Allow tabs to get smaller when the available space is not enough to show all tabs at once.") + ], + 'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'tabSizing' }, "Controls the sizing of editor tabs.") + }, + 'workbench.editor.focusRecentEditorAfterClose': { + 'type': 'boolean', + 'description': nls.localize('focusRecentEditorAfterClose', "Controls whether tabs are closed in most recently used order or from left to right."), + 'default': true + }, + 'workbench.editor.showIcons': { + 'type': 'boolean', + 'description': nls.localize('showIcons', "Controls whether opened editors should show with an icon or not. This requires an icon theme to be enabled as well."), + 'default': true + }, + 'workbench.editor.enablePreview': { + 'type': 'boolean', + 'description': nls.localize('enablePreview', "Controls whether opened editors show as preview. Preview editors are reused until they are pinned (e.g. via double click or editing) and show up with an italic font style."), + 'default': true + }, + 'workbench.editor.enablePreviewFromQuickOpen': { + 'type': 'boolean', + 'description': nls.localize('enablePreviewFromQuickOpen', "Controls whether opened editors from Quick Open show as preview. Preview editors are reused until they are pinned (e.g. via double click or editing)."), + 'default': true + }, + 'workbench.editor.closeOnFileDelete': { + 'type': 'boolean', + 'description': nls.localize('closeOnFileDelete', "Controls whether editors showing a file that was opened during the session should close automatically when getting deleted or renamed by some other process. Disabling this will keep the editor open on such an event. Note that deleting from within the application will always close the editor and that dirty files will never close to preserve your data."), + 'default': false + }, + 'workbench.editor.openPositioning': { + 'type': 'string', + 'enum': ['left', 'right', 'first', 'last'], + 'default': 'right', + 'markdownDescription': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorOpenPositioning' }, "Controls where editors open. Select `left` or `right` to open editors to the left or right of the currently active one. Select `first` or `last` to open editors independently from the currently active one.") + }, + 'workbench.editor.openSideBySideDirection': { + 'type': 'string', + 'enum': ['right', 'down'], + 'default': 'right', + 'markdownDescription': nls.localize('sideBySideDirection', "Controls the default direction of editors that are opened side by side (e.g. from the explorer). By default, editors will open on the right hand side of the currently active one. If changed to `down`, the editors will open below the currently active one.") + }, + 'workbench.editor.closeEmptyGroups': { + 'type': 'boolean', + 'description': nls.localize('closeEmptyGroups', "Controls the behavior of empty editor groups when the last tab in the group is closed. When enabled, empty groups will automatically close. When disabled, empty groups will remain part of the grid."), + 'default': true + }, + 'workbench.editor.revealIfOpen': { + 'type': 'boolean', + 'description': nls.localize('revealIfOpen', "Controls whether an editor is revealed in any of the visible groups if opened. If disabled, an editor will prefer to open in the currently active editor group. If enabled, an already opened editor will be revealed instead of opened again in the currently active editor group. Note that there are some cases where this setting is ignored, e.g. when forcing an editor to open in a specific group or to the side of the currently active group."), + 'default': false + }, + 'workbench.editor.swipeToNavigate': { + 'type': 'boolean', + 'description': nls.localize('swipeToNavigate', "Navigate between open files using three-finger swipe horizontally."), + 'default': false, + 'included': isMacintosh + }, + 'workbench.editor.restoreViewState': { + 'type': 'boolean', + 'description': nls.localize('restoreViewState', "Restores the last view state (e.g. scroll position) when re-opening files after they have been closed."), + 'default': true, + }, + 'workbench.editor.centeredLayoutAutoResize': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('centeredLayoutAutoResize', "Controls if the centered layout should automatically resize to maximum width when more than one group is open. Once only one group is open it will resize back to the original centered width.") + }, + 'workbench.commandPalette.history': { + 'type': 'number', + 'description': nls.localize('commandHistory', "Controls the number of recently used commands to keep in history for the command palette. Set to 0 to disable command history."), + 'default': 50 + }, + 'workbench.commandPalette.preserveInput': { + 'type': 'boolean', + 'description': nls.localize('preserveInput', "Controls whether the last typed input to the command palette should be restored when opening it the next time."), + 'default': false + }, + 'workbench.quickOpen.closeOnFocusLost': { + 'type': 'boolean', + 'description': nls.localize('closeOnFocusLost', "Controls whether Quick Open should close automatically once it loses focus."), + 'default': true + }, + 'workbench.quickOpen.preserveInput': { + 'type': 'boolean', + 'description': nls.localize('workbench.quickOpen.preserveInput', "Controls whether the last typed input to Quick Open should be restored when opening it the next time."), + 'default': false + }, + 'workbench.settings.openDefaultSettings': { + 'type': 'boolean', + 'description': nls.localize('openDefaultSettings', "Controls whether opening settings also opens an editor showing all default settings."), + 'default': false + }, + 'workbench.settings.useSplitJSON': { + 'type': 'boolean', + 'markdownDescription': nls.localize('useSplitJSON', "Controls whether to use the split JSON editor when editing settings as JSON."), + 'default': false + }, + 'workbench.settings.openDefaultKeybindings': { + 'type': 'boolean', + 'description': nls.localize('openDefaultKeybindings', "Controls whether opening keybinding settings also opens an editor showing all default keybindings."), + 'default': false + }, + 'workbench.sideBar.location': { + 'type': 'string', + 'enum': ['left', 'right'], + 'default': 'left', + 'description': nls.localize('sideBarLocation', "Controls the location of the sidebar. It can either show on the left or right of the workbench.") + }, + 'workbench.panel.defaultLocation': { + 'type': 'string', + 'enum': ['bottom', 'right'], + 'default': 'bottom', + 'description': nls.localize('panelDefaultLocation', "Controls the default location of the panel (terminal, debug console, output, problems). It can either show at the bottom or on the right of the workbench.") + }, + 'workbench.statusBar.visible': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('statusBarVisibility', "Controls the visibility of the status bar at the bottom of the workbench.") + }, + 'workbench.activityBar.visible': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('activityBarVisibility', "Controls the visibility of the activity bar in the workbench.") + }, + 'workbench.view.alwaysShowHeaderActions': { + 'type': 'boolean', + 'default': false, + 'description': nls.localize('viewVisibility', "Controls the visibility of view header actions. View header actions may either be always visible, or only visible when that view is focused or hovered over.") + }, + 'workbench.fontAliasing': { + 'type': 'string', + 'enum': ['default', 'antialiased', 'none', 'auto'], + 'default': 'default', + 'description': + nls.localize('fontAliasing', "Controls font aliasing method in the workbench."), + 'enumDescriptions': [ + nls.localize('workbench.fontAliasing.default', "Sub-pixel font smoothing. On most non-retina displays this will give the sharpest text."), + nls.localize('workbench.fontAliasing.antialiased', "Smooth the font on the level of the pixel, as opposed to the subpixel. Can make the font appear lighter overall."), + nls.localize('workbench.fontAliasing.none', "Disables font smoothing. Text will show with jagged sharp edges."), + nls.localize('workbench.fontAliasing.auto', "Applies `default` or `antialiased` automatically based on the DPI of displays.") + ], + 'included': isMacintosh + }, + 'workbench.settings.enableNaturalLanguageSearch': { + 'type': 'boolean', + 'description': nls.localize('enableNaturalLanguageSettingsSearch', "Controls whether to enable the natural language search mode for settings. The natural language search is provided by a Microsoft online service."), + 'default': true, + 'scope': ConfigurationScope.WINDOW, + 'tags': ['usesOnlineServices'] + }, + 'workbench.settings.settingsSearchTocBehavior': { + 'type': 'string', + 'enum': ['hide', 'filter'], + 'enumDescriptions': [ + nls.localize('settingsSearchTocBehavior.hide', "Hide the Table of Contents while searching."), + nls.localize('settingsSearchTocBehavior.filter', "Filter the Table of Contents to just categories that have matching settings. Clicking a category will filter the results to that category."), + ], + 'description': nls.localize('settingsSearchTocBehavior', "Controls the behavior of the settings editor Table of Contents while searching."), + 'default': 'filter', + 'scope': ConfigurationScope.WINDOW + }, + 'workbench.settings.editor': { + 'type': 'string', + 'enum': ['ui', 'json'], + 'enumDescriptions': [ + nls.localize('settings.editor.ui', "Use the settings UI editor."), + nls.localize('settings.editor.json', "Use the JSON file editor."), + ], + 'description': nls.localize('settings.editor.desc', "Determines which settings editor to use by default."), + 'default': 'ui', + 'scope': ConfigurationScope.WINDOW + }, + 'workbench.enableExperiments': { + 'type': 'boolean', + 'description': nls.localize('workbench.enableExperiments', "Fetches experiments to run from a Microsoft online service."), + 'default': true, + 'tags': ['usesOnlineServices'] + }, + 'workbench.useExperimentalGridLayout': { + 'type': 'boolean', + 'description': nls.localize('workbench.useExperimentalGridLayout', "Enables the grid layout for the workbench. This setting may enable additional layout options for workbench components."), + 'default': false, + 'scope': ConfigurationScope.APPLICATION + } } - } -}); + }); -// Configuration: Zen Mode -configurationRegistry.registerConfiguration({ - 'id': 'zenMode', - 'order': 9, - 'title': nls.localize('zenModeConfigurationTitle', "Zen Mode"), - 'type': 'object', - 'properties': { - 'zenMode.fullScreen': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('zenMode.fullScreen', "Controls whether turning on Zen Mode also puts the workbench into full screen mode.") - }, - 'zenMode.centerLayout': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('zenMode.centerLayout', "Controls whether turning on Zen Mode also centers the layout.") - }, - 'zenMode.hideTabs': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('zenMode.hideTabs', "Controls whether turning on Zen Mode also hides workbench tabs.") - }, - 'zenMode.hideStatusBar': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('zenMode.hideStatusBar', "Controls whether turning on Zen Mode also hides the status bar at the bottom of the workbench.") - }, - 'zenMode.hideActivityBar': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('zenMode.hideActivityBar', "Controls whether turning on Zen Mode also hides the activity bar at the left of the workbench.") - }, - 'zenMode.hideLineNumbers': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('zenMode.hideLineNumbers', "Controls whether turning on Zen Mode also hides the editor line numbers.") - }, - 'zenMode.restore': { - 'type': 'boolean', - 'default': false, - 'description': nls.localize('zenMode.restore', "Controls whether a window should restore to zen mode if it was exited in zen mode.") + // Zen Mode + registry.registerConfiguration({ + 'id': 'zenMode', + 'order': 9, + 'title': nls.localize('zenModeConfigurationTitle', "Zen Mode"), + 'type': 'object', + 'properties': { + 'zenMode.fullScreen': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('zenMode.fullScreen', "Controls whether turning on Zen Mode also puts the workbench into full screen mode.") + }, + 'zenMode.centerLayout': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('zenMode.centerLayout', "Controls whether turning on Zen Mode also centers the layout.") + }, + 'zenMode.hideTabs': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('zenMode.hideTabs', "Controls whether turning on Zen Mode also hides workbench tabs.") + }, + 'zenMode.hideStatusBar': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('zenMode.hideStatusBar', "Controls whether turning on Zen Mode also hides the status bar at the bottom of the workbench.") + }, + 'zenMode.hideActivityBar': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('zenMode.hideActivityBar', "Controls whether turning on Zen Mode also hides the activity bar at the left of the workbench.") + }, + 'zenMode.hideLineNumbers': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('zenMode.hideLineNumbers', "Controls whether turning on Zen Mode also hides the editor line numbers.") + }, + 'zenMode.restore': { + 'type': 'boolean', + 'default': false, + 'description': nls.localize('zenMode.restore', "Controls whether a window should restore to zen mode if it was exited in zen mode.") + } } - } -}); \ No newline at end of file + }); +})(); \ No newline at end of file diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts b/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts index 4a4660744e7..e4bef65fcc3 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts @@ -299,8 +299,8 @@ registerEditorAction(GoToPreviousBreakpointAction); MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: RunToCursorAction.ID, - title: RunToCursorAction.LABEL, - category: 'Debug' + title: { value: RunToCursorAction.LABEL, original: 'Debug: Run to Cursor' }, + category: nls.localize('debug', "Debug") }, group: 'debug', when: ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')), diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorModelManager.ts b/src/vs/workbench/contrib/debug/browser/debugEditorModelManager.ts index 20b921632d2..59433d2e6ae 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorModelManager.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorModelManager.ts @@ -127,27 +127,20 @@ export class DebugEditorModelManager implements IWorkbenchContribution { range }); - if (stackFrame.thread.stoppedDetails && stackFrame.thread.stoppedDetails.reason === 'exception') { - result.push({ - options: DebugEditorModelManager.TOP_STACK_FRAME_EXCEPTION_DECORATION, - range: columnUntilEOLRange - }); - } else { - result.push({ - options: DebugEditorModelManager.TOP_STACK_FRAME_DECORATION, - range: columnUntilEOLRange - }); + result.push({ + options: DebugEditorModelManager.TOP_STACK_FRAME_DECORATION, + range: columnUntilEOLRange + }); - if (this.modelDataMap.has(modelUriStr)) { - const modelData = this.modelDataMap.get(modelUriStr); - if (modelData.topStackFrameRange && modelData.topStackFrameRange.startLineNumber === stackFrame.range.startLineNumber && modelData.topStackFrameRange.startColumn !== stackFrame.range.startColumn) { - result.push({ - options: DebugEditorModelManager.TOP_STACK_FRAME_INLINE_DECORATION, - range: columnUntilEOLRange - }); - } - modelData.topStackFrameRange = columnUntilEOLRange; + if (this.modelDataMap.has(modelUriStr)) { + const modelData = this.modelDataMap.get(modelUriStr); + if (modelData.topStackFrameRange && modelData.topStackFrameRange.startLineNumber === stackFrame.range.startLineNumber && modelData.topStackFrameRange.startColumn !== stackFrame.range.startColumn) { + result.push({ + options: DebugEditorModelManager.TOP_STACK_FRAME_INLINE_DECORATION, + range: columnUntilEOLRange + }); } + modelData.topStackFrameRange = columnUntilEOLRange; } } else { result.push({ @@ -307,13 +300,6 @@ export class DebugEditorModelManager implements IWorkbenchContribution { stickiness: DebugEditorModelManager.STICKINESS }; - private static TOP_STACK_FRAME_EXCEPTION_DECORATION: IModelDecorationOptions = { - isWholeLine: true, - inlineClassName: 'debug-remove-token-colors', - className: 'debug-top-stack-frame-exception-line', - stickiness: DebugEditorModelManager.STICKINESS - }; - private static TOP_STACK_FRAME_INLINE_DECORATION: IModelDecorationOptions = { beforeContentClassName: 'debug-top-stack-frame-column' }; diff --git a/src/vs/workbench/contrib/debug/browser/media/exceptionWidget.css b/src/vs/workbench/contrib/debug/browser/media/exceptionWidget.css index 14e674738d5..904f20bd1d5 100644 --- a/src/vs/workbench/contrib/debug/browser/media/exceptionWidget.css +++ b/src/vs/workbench/contrib/debug/browser/media/exceptionWidget.css @@ -24,6 +24,7 @@ .monaco-editor .zone-widget .zone-widget-container.exception-widget .stack-trace { margin-top: 0.5em; + max-height: 500px; } .monaco-editor .zone-widget .zone-widget-container.exception-widget a { diff --git a/src/vs/workbench/contrib/debug/browser/media/repl.css b/src/vs/workbench/contrib/debug/browser/media/repl.css index afb6ca59a78..a422734f2a4 100644 --- a/src/vs/workbench/contrib/debug/browser/media/repl.css +++ b/src/vs/workbench/contrib/debug/browser/media/repl.css @@ -11,16 +11,6 @@ overflow: hidden; } -.repl .surveyor { - font-family: var(--monaco-monospace-font); - position: absolute; - display: inline-block; - width : auto; - top: 0; - left: 0; - visibility: hidden; -} - /* Align twisite to last line - for input output pair expressions. */ .repl .repl-tree .monaco-tl-twistie { background-position-y: calc(100% - 2px); diff --git a/src/vs/workbench/contrib/debug/electron-browser/callStackView.ts b/src/vs/workbench/contrib/debug/electron-browser/callStackView.ts index ae804608a8c..2cb9b43301b 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/callStackView.ts @@ -234,7 +234,7 @@ export class CallStackView extends ViewletPanel { } private updateTreeSelection(): void { - if (!this.tree || this.tree.visibleNodeCount === 0) { + if (!this.tree || !this.tree.getInput()) { // Tree not initialized yet return; } diff --git a/src/vs/workbench/contrib/debug/electron-browser/debugHover.ts b/src/vs/workbench/contrib/debug/electron-browser/debugHover.ts index 5f607046ec1..afd0ac87f2d 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/debugHover.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/debugHover.ts @@ -253,7 +253,7 @@ export class DebugHoverWidget implements IContentWidget { } private layoutTreeAndContainer(): void { - const treeHeight = Math.min(MAX_TREE_HEIGHT, this.tree.visibleNodeCount * 18); + const treeHeight = Math.min(MAX_TREE_HEIGHT, this.tree.contentHeight); this.treeContainer.style.height = `${treeHeight}px`; this.tree.layout(treeHeight, 324); } diff --git a/src/vs/workbench/contrib/debug/electron-browser/debugSession.ts b/src/vs/workbench/contrib/debug/electron-browser/debugSession.ts index 5757eb26e15..01a06615c87 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/debugSession.ts @@ -32,6 +32,7 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel'; import { onUnexpectedError } from 'vs/base/common/errors'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { INotificationService } from 'vs/platform/notification/common/notification'; export class DebugSession implements IDebugSession { private id: string; @@ -62,7 +63,8 @@ export class DebugSession implements IDebugSession { @IConfigurationService private readonly configurationService: IConfigurationService, @IViewletService private readonly viewletService: IViewletService, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, - @IEnvironmentService private readonly environmentService: IEnvironmentService + @IEnvironmentService private readonly environmentService: IEnvironmentService, + @INotificationService private readonly notificationService: INotificationService ) { this.id = generateUuid(); this.repl = new ReplModel(this); @@ -591,7 +593,7 @@ export class DebugSession implements IDebugSession { this.raw.disconnect(); } if (e.command !== 'canceled' && e.message !== 'canceled') { - onUnexpectedError(e); + this.notificationService.error(e); } }); } diff --git a/src/vs/workbench/contrib/debug/electron-browser/repl.ts b/src/vs/workbench/contrib/debug/electron-browser/repl.ts index b8c71e5aad5..17186274d8c 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/repl.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/repl.ts @@ -10,7 +10,6 @@ import * as errors from 'vs/base/common/errors'; import { IAction, IActionItem, Action } from 'vs/base/common/actions'; import * as dom from 'vs/base/browser/dom'; import * as aria from 'vs/base/browser/ui/aria/aria'; -import { isMacintosh } from 'vs/base/common/platform'; import { CancellationToken } from 'vs/base/common/cancellation'; import { KeyCode } from 'vs/base/common/keyCodes'; import severity from 'vs/base/common/severity'; @@ -60,7 +59,7 @@ import { CopyAction } from 'vs/workbench/contrib/debug/electron-browser/electron import { ReplCollapseAllAction } from 'vs/workbench/contrib/debug/browser/debugActions'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { removeAnsiEscapeCodes, isFullWidthCharacter, endsWith } from 'vs/base/common/strings'; +import { removeAnsiEscapeCodes } from 'vs/base/common/strings'; import { WorkbenchAsyncDataTree, IListService } from 'vs/platform/list/browser/listService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; @@ -91,7 +90,6 @@ const sessionsToIgnore = new Set(); export class Repl extends Panel implements IPrivateReplService, IHistoryNavigationWidget { _serviceBrand: any; - private static readonly HALF_WIDTH_TYPICAL = 'n'; 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; private static readonly REPL_INPUT_MAX_HEIGHT = 170; @@ -268,7 +266,6 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati layout(dimension: dom.Dimension): void { this.dimension = dimension; if (this.tree) { - this.replDelegate.setWidth(dimension.width - 25, this.characterWidth); const treeHeight = dimension.height - this.replInputHeight; this.treeContainer.style.height = `${treeHeight}px`; this.tree.layout(treeHeight, dimension.width); @@ -303,18 +300,6 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } // --- Cached locals - @memoize - private get characterWidth(): number { - const characterWidthSurveyor = dom.append(this.container, $('.surveyor')); - characterWidthSurveyor.textContent = Repl.HALF_WIDTH_TYPICAL; - for (let i = 0; i < 10; i++) { - characterWidthSurveyor.textContent += characterWidthSurveyor.textContent; - } - characterWidthSurveyor.style.fontSize = isMacintosh ? '12px' : '14px'; - - return characterWidthSurveyor.clientWidth / characterWidthSurveyor.textContent.length; - } - @memoize private get selectReplAction(): SelectReplAction { return this.scopedInstantiationService.createInstance(SelectReplAction, SelectReplAction.ID, SelectReplAction.LABEL); @@ -361,7 +346,8 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati identityProvider: { getId: element => element.getId() }, mouseSupport: false, keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: e => e }, - horizontalScrolling: false + horizontalScrolling: false, + supportDynamicHeights: true }, this.contextKeyService, this.listService, this.themeService, this.configurationService, this.keybindingService); this.toDispose.push(this.tree.onContextMenu(e => this.onContextMenu(e))); @@ -683,23 +669,12 @@ class ReplDelegate implements IListVirtualDelegate { private static readonly LINE_HEIGHT_PX = 18; - private width: number; - private characterWidth: number; - getHeight(element: IReplElement): number { - if (element instanceof Variable && (element.hasChildren || (element.name !== null))) { - return ReplDelegate.LINE_HEIGHT_PX; - } if (element instanceof Expression && element.hasChildren) { return 2 * ReplDelegate.LINE_HEIGHT_PX; } - let availableWidth = this.width; - if (element instanceof SimpleReplElement && element.sourceData) { - availableWidth -= Math.ceil(`${element.sourceData.source.name}:${element.sourceData.lineNumber}`.length * this.characterWidth + 12); - } - - return this.getHeightForString((element).value, availableWidth) + (element instanceof Expression ? this.getHeightForString(element.name, availableWidth) : 0); + return ReplDelegate.LINE_HEIGHT_PX; } getTemplateId(element: IReplElement): string { @@ -721,35 +696,7 @@ class ReplDelegate implements IListVirtualDelegate { } hasDynamicHeight?(element: IReplElement): boolean { - // todo@isidor - return false; - } - - private getHeightForString(s: string, availableWidth: number): number { - if (!s || !s.length || !availableWidth || availableWidth <= 0 || !this.characterWidth || this.characterWidth <= 0) { - return ReplDelegate.LINE_HEIGHT_PX; - } - - // Last new line should be ignored since the repl elements are by design split by rows - if (endsWith(s, '\n')) { - s = s.substr(0, s.length - 1); - } - const lines = removeAnsiEscapeCodes(s).split('\n'); - const numLines = lines.reduce((lineCount: number, line: string) => { - let lineLength = 0; - for (let i = 0; i < line.length; i++) { - lineLength += isFullWidthCharacter(line.charCodeAt(i)) ? 2 : 1; - } - - return lineCount + Math.floor(lineLength * this.characterWidth / availableWidth); - }, lines.length); - - return ReplDelegate.LINE_HEIGHT_PX * numLines; - } - - setWidth(fullWidth: number, characterWidth: number): void { - this.width = fullWidth; - this.characterWidth = characterWidth; + return true; } } diff --git a/src/vs/workbench/contrib/debug/test/electron-browser/debugModel.test.ts b/src/vs/workbench/contrib/debug/test/electron-browser/debugModel.test.ts index 03ae2794d6d..d274e7916f0 100644 --- a/src/vs/workbench/contrib/debug/test/electron-browser/debugModel.test.ts +++ b/src/vs/workbench/contrib/debug/test/electron-browser/debugModel.test.ts @@ -110,7 +110,7 @@ suite('Debug - Model', () => { test('threads simple', () => { const threadId = 1; const threadName = 'firstThread'; - const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); + const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); model.addSession(session); assert.equal(model.getSessions(true).length, 1); @@ -138,7 +138,7 @@ suite('Debug - Model', () => { const stoppedReason = 'breakpoint'; // Add the threads - const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); + const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); model.addSession(session); session['raw'] = rawSession; @@ -225,7 +225,7 @@ suite('Debug - Model', () => { const runningThreadId = 2; const runningThreadName = 'runningThread'; const stoppedReason = 'breakpoint'; - const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); + const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); model.addSession(session); session['raw'] = rawSession; @@ -338,7 +338,7 @@ suite('Debug - Model', () => { }); test('repl expressions', () => { - const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); + const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); assert.equal(session.getReplElements().length, 0); model.addSession(session); @@ -362,7 +362,7 @@ suite('Debug - Model', () => { }); test('stack frame get specific source name', () => { - const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); + const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); model.addSession(session); let firstStackFrame: StackFrame; @@ -393,7 +393,7 @@ suite('Debug - Model', () => { // Repl output test('repl output', () => { - const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); + const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); const repl = new ReplModel(session); repl.appendToRepl('first line\n', severity.Error); repl.appendToRepl('second line', severity.Error); diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts index 753676567a1..54f6af6c0d4 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts @@ -533,7 +533,9 @@ export class ExtensionEditor extends BaseEditor { .then(body => { const wbeviewElement = this.instantiationService.createInstance(WebviewElement, this.partService.getContainer(Parts.EDITOR_PART), - {}, + { + enableFindWidget: true, + }, { svgWhiteList: this.extensionsWorkbenchService.allowedBadgeProviders }); diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts index 5c8039ed632..f909b93fb74 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts @@ -1125,7 +1125,7 @@ export class ReloadAction extends ExtensionAction { export class SetColorThemeAction extends ExtensionAction { static getColorThemes(colorThemes: IColorTheme[], extension: IExtension): IColorTheme[] { - return colorThemes.filter(c => ExtensionIdentifier.equals(c.extensionData.extensionId, extension.identifier.id)); + return colorThemes.filter(c => c.extensionData && ExtensionIdentifier.equals(c.extensionData.extensionId, extension.identifier.id)); } private static readonly EnabledClass = 'extension-action theme'; @@ -1784,6 +1784,7 @@ export class ConfigureRecommendedExtensionsCommandsContributor extends Disposabl command: { id: ConfigureWorkspaceRecommendedExtensionsAction.ID, title: { value: `${ExtensionsLabel}: ${ConfigureWorkspaceRecommendedExtensionsAction.LABEL}`, original: 'Extensions: Configure Recommended Extensions (Workspace)' }, + category: localize('extensions', "Extensions") }, when: this.workspaceContextKey }); @@ -1795,6 +1796,7 @@ export class ConfigureRecommendedExtensionsCommandsContributor extends Disposabl command: { id: ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, title: { value: `${ExtensionsLabel}: ${ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL}`, original: 'Extensions: Configure Recommended Extensions (Workspace Folder)' }, + category: localize('extensions', "Extensions") }, when: this.workspaceFolderContextKey }); @@ -1807,7 +1809,8 @@ export class ConfigureRecommendedExtensionsCommandsContributor extends Disposabl MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: AddToWorkspaceRecommendationsAction.ADD_ID, - title: { value: `${ExtensionsLabel}: ${AddToWorkspaceRecommendationsAction.ADD_LABEL}`, original: 'Extensions: Add to Recommended Extensions (Workspace)' } + title: { value: `${ExtensionsLabel}: ${AddToWorkspaceRecommendationsAction.ADD_LABEL}`, original: 'Extensions: Add to Recommended Extensions (Workspace)' }, + category: localize('extensions', "Extensions") }, when: this.addToWorkspaceRecommendationsContextKey }); @@ -1820,7 +1823,8 @@ export class ConfigureRecommendedExtensionsCommandsContributor extends Disposabl MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: AddToWorkspaceFolderRecommendationsAction.ADD_ID, - title: { value: `${ExtensionsLabel}: ${AddToWorkspaceFolderRecommendationsAction.ADD_LABEL}`, original: 'Extensions: Add to Recommended Extensions (Workspace Folder)' } + title: { value: `${ExtensionsLabel}: ${AddToWorkspaceFolderRecommendationsAction.ADD_LABEL}`, original: 'Extensions: Add to Recommended Extensions (Workspace Folder)' }, + category: localize('extensions', "Extensions") }, when: this.addToWorkspaceFolderRecommendationsContextKey }); @@ -1833,7 +1837,8 @@ export class ConfigureRecommendedExtensionsCommandsContributor extends Disposabl MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: AddToWorkspaceRecommendationsAction.IGNORE_ID, - title: { value: `${ExtensionsLabel}: ${AddToWorkspaceRecommendationsAction.IGNORE_LABEL}`, original: 'Extensions: Ignore Recommended Extension (Workspace)' } + title: { value: `${ExtensionsLabel}: ${AddToWorkspaceRecommendationsAction.IGNORE_LABEL}`, original: 'Extensions: Ignore Recommended Extension (Workspace)' }, + category: localize('extensions', "Extensions") }, when: this.addToWorkspaceRecommendationsContextKey }); @@ -1846,7 +1851,8 @@ export class ConfigureRecommendedExtensionsCommandsContributor extends Disposabl MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: AddToWorkspaceFolderRecommendationsAction.IGNORE_ID, - title: { value: `${ExtensionsLabel}: ${AddToWorkspaceFolderRecommendationsAction.IGNORE_LABEL}`, original: 'Extensions: Ignore Recommended Extension (Workspace Folder)' } + title: { value: `${ExtensionsLabel}: ${AddToWorkspaceFolderRecommendationsAction.IGNORE_LABEL}`, original: 'Extensions: Ignore Recommended Extension (Workspace Folder)' }, + category: localize('extensions', "Extensions") }, when: this.addToWorkspaceFolderRecommendationsContextKey }); diff --git a/src/vs/workbench/contrib/files/electron-browser/views/explorerView.ts b/src/vs/workbench/contrib/files/electron-browser/views/explorerView.ts index 67e96e37989..c1ef97915b9 100644 --- a/src/vs/workbench/contrib/files/electron-browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/electron-browser/views/explorerView.ts @@ -26,7 +26,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ResourceContextKey } from 'vs/workbench/common/resources'; import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; -import { WorkbenchAsyncDataTree, IListService } from 'vs/platform/list/browser/listService'; +import { WorkbenchAsyncDataTree, IListService, TreeResourceNavigator2 } from 'vs/platform/list/browser/listService'; import { DelayedDragHandler } from 'vs/base/browser/dnd'; import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IViewletPanelOptions, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet'; @@ -314,18 +314,13 @@ export class ExplorerView extends ViewletPanel { this.rootContext.set(!stat || (stat && stat.isRoot)); })); - // TODO@Isidor: use TreeResourceNavigator2 just like search and listen to the `onDidOpenResource` instead - + const explorerNavigator = new TreeResourceNavigator2(this.tree); + this.disposables.push(explorerNavigator); // Open when selecting via keyboard - this.disposables.push(this.tree.onDidChangeSelection(e => { - if (!e.browserEvent) { - // Only react on selection change events caused by user interaction (ignore those which are caused by us doing tree.setSelection). - return; - } - const selection = e.elements; + this.disposables.push(explorerNavigator.onDidOpenResource(e => { + const selection = this.tree.getSelection(); // Do not react if the user is expanding selection via keyboard. // Check if the item was previously also selected, if yes the user is simply expanding / collapsing current selection #66589. - const shiftDown = e.browserEvent instanceof KeyboardEvent && e.browserEvent.shiftKey; if (selection.length === 1 && !shiftDown) { // Do not react if user is clicking on explorer items which are input placeholders @@ -339,23 +334,7 @@ export class ExplorerView extends ViewletPanel { } return; } - let isDoubleClick = false; - let sideBySide = false; - let isMiddleClick = false; - if (e.browserEvent instanceof MouseEvent) { - isDoubleClick = e.browserEvent.detail === 2; - isMiddleClick = e.browserEvent.button === 1; - const isLeftButton = e.browserEvent.button === 0; - - if (isLeftButton && !this.tree.openOnSingleClick && !isDoubleClick) { - return; - } - - sideBySide = this.tree.useAltAsMultipleSelectionModifier ? (e.browserEvent.ctrlKey || e.browserEvent.metaKey) : e.browserEvent.altKey; - } - - // Pass focus for keyboard events and for double click /* __GDPR__ "workbenchActionExecuted" : { "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, @@ -363,7 +342,7 @@ export class ExplorerView extends ViewletPanel { }*/ this.telemetryService.publicLog('workbenchActionExecuted', { id: 'workbench.files.openFile', from: 'explorer' }); this.ignoreActiveEditorChange = true; - this.editorService.openEditor({ resource: selection[0].resource, options: { preserveFocus: (e.browserEvent instanceof MouseEvent) && !isDoubleClick, pinned: isDoubleClick || isMiddleClick } }, sideBySide ? SIDE_GROUP : ACTIVE_GROUP) + this.editorService.openEditor({ resource: selection[0].resource, options: { preserveFocus: e.editorOptions.preserveFocus, pinned: e.editorOptions.pinned } }, e.sideBySide ? SIDE_GROUP : ACTIVE_GROUP) .then(undefined, onUnexpectedError); } })); diff --git a/src/vs/workbench/contrib/files/electron-browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/electron-browser/views/explorerViewer.ts index 8c253e50a35..e4515c8b522 100644 --- a/src/vs/workbench/contrib/files/electron-browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/electron-browser/views/explorerViewer.ts @@ -755,7 +755,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { uri: folders[index].uri }; if (target instanceof ExplorerItem && folders[index].uri.toString() === target.resource.toString()) { - targetIndex = workspaceCreationData.length; + targetIndex = index; } if (roots.every(r => r.resource.toString() !== folders[index].uri.toString())) { diff --git a/src/vs/workbench/contrib/files/electron-browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/electron-browser/views/openEditorsView.ts index 3e610aba897..99b54b31610 100644 --- a/src/vs/workbench/contrib/files/electron-browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/electron-browser/views/openEditorsView.ts @@ -253,7 +253,7 @@ export class OpenEditorsView extends ViewletPanel { // Open when selecting via keyboard this.disposables.push(this.list.onMouseMiddleClick(e => { if (e && e.element instanceof OpenEditor) { - e.element.group.closeEditor(e.element.editor); + e.element.group.closeEditor(e.element.editor, { preserveFocus: true }); } })); this.disposables.push(this.list.onDidOpen(e => { diff --git a/src/vs/workbench/contrib/markers/electron-browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/electron-browser/markers.contribution.ts index 3b0941c9085..dfd479d4c5a 100644 --- a/src/vs/workbench/contrib/markers/electron-browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/electron-browser/markers.contribution.ts @@ -14,7 +14,7 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { localize } from 'vs/nls'; import { Marker, RelatedInformation } from 'vs/workbench/contrib/markers/electron-browser/markersModel'; import { MarkersPanel } from 'vs/workbench/contrib/markers/electron-browser/markersPanel'; -import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { MenuId, MenuRegistry, SyncActionDescriptor, ILocalizedString } from 'vs/platform/actions/common/actions'; import { PanelRegistry, Extensions as PanelExtensions, PanelDescriptor } from 'vs/workbench/browser/panel'; import { Registry } from 'vs/platform/registry/common/platform'; import { ToggleMarkersPanelAction, ShowProblemsPanelAction } from 'vs/workbench/contrib/markers/electron-browser/markersPanelActions'; @@ -105,7 +105,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMarkersPanelActi registry.registerWorkbenchAction(new SyncActionDescriptor(ShowProblemsPanelAction, ShowProblemsPanelAction.ID, ShowProblemsPanelAction.LABEL), 'View: Focus Problems (Errors, Warnings, Infos)', Messages.MARKERS_PANEL_VIEW_CATEGORY); registerAction({ id: Constants.MARKER_COPY_ACTION_ID, - title: localize('copyMarker', "Copy"), + title: { value: localize('copyMarker', "Copy"), original: 'Copy' }, handler(accessor) { copyMarker(accessor.get(IPanelService)); }, @@ -123,7 +123,7 @@ registerAction({ }); registerAction({ id: Constants.MARKER_COPY_MESSAGE_ACTION_ID, - title: localize('copyMessage', "Copy Message"), + title: { value: localize('copyMessage', "Copy Message"), original: 'Copy Message' }, handler(accessor) { copyMessage(accessor.get(IPanelService)); }, @@ -135,7 +135,7 @@ registerAction({ }); registerAction({ id: Constants.RELATED_INFORMATION_COPY_MESSAGE_ACTION_ID, - title: localize('copyMessage', "Copy Message"), + title: { value: localize('copyMessage', "Copy Message"), original: 'Copy Message' }, handler(accessor) { copyRelatedInformationMessage(accessor.get(IPanelService)); }, @@ -178,7 +178,7 @@ registerAction({ panel.markersViewModel.multiline = true; } }, - title: localize('show multiline', "Show message in multiple lines"), + title: { value: localize('show multiline', "Show message in multiple lines"), original: 'Problems: Show message in multiple lines' }, category: localize('problems', "Problems"), menu: { menuId: MenuId.CommandPalette, @@ -194,7 +194,7 @@ registerAction({ panel.markersViewModel.multiline = false; } }, - title: localize('show singleline', "Show message in single line"), + title: { value: localize('show singleline', "Show message in single line"), original: 'Problems: Show message in single line' }, category: localize('problems', "Problems"), menu: { menuId: MenuId.CommandPalette, @@ -251,7 +251,7 @@ interface IActionDescriptor { handler: ICommandHandler; // ICommandUI - title?: string; + title?: ILocalizedString; category?: string; f1?: boolean; diff --git a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts index eac6760bc34..127e923c645 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts @@ -72,10 +72,10 @@ class RequestOracle { private _disposables = new Array(); private _sessionDisposable: IDisposable; - private _lastState: RequestState; + private _lastState?: RequestState; constructor( - private readonly _callback: (editor: ICodeEditor, change: IModelContentChangedEvent) => any, + private readonly _callback: (editor: ICodeEditor | undefined, change: IModelContentChangedEvent | undefined) => any, private readonly _featureRegistry: LanguageFeatureRegistry, @IEditorService private readonly _editorService: IEditorService, ) { @@ -99,7 +99,7 @@ class RequestOracle { codeEditor = widget.getModifiedEditor(); } - if (!codeEditor || !codeEditor.getModel()) { + if (!codeEditor || !codeEditor.hasModel()) { this._lastState = undefined; this._callback(undefined, undefined); return; @@ -112,7 +112,7 @@ class RequestOracle { this._featureRegistry.all(codeEditor.getModel()).length ); - if (thisState.equals(this._lastState)) { + if (this._lastState && thisState.equals(this._lastState)) { // prevent unneccesary changes... return; } @@ -123,10 +123,10 @@ class RequestOracle { let handle: any; let contentListener = codeEditor.onDidChangeModelContent(event => { clearTimeout(handle); - handle = setTimeout(() => this._callback(codeEditor, event), 350); + handle = setTimeout(() => this._callback(codeEditor!, event), 350); }); let modeListener = codeEditor.onDidChangeModelLanguage(_ => { - this._callback(codeEditor, undefined); + this._callback(codeEditor!, undefined); }); let disposeListener = codeEditor.onDidDispose(() => { this._callback(undefined, undefined); @@ -145,10 +145,10 @@ class RequestOracle { class SimpleToggleAction extends Action { constructor(label: string, checked: boolean, callback: (action: SimpleToggleAction) => any, className?: string) { - super(`simple` + defaultGenerator.nextId(), label, className, true, _ => { + super(`simple` + defaultGenerator.nextId(), label, className, true, () => { this.checked = !this.checked; callback(this); - return undefined; + return Promise.resolve(); }); this.checked = checked; } @@ -223,7 +223,7 @@ export class OutlinePanel extends ViewletPanel { private _editorDisposables = new Array(); private _outlineViewState = new OutlineViewState(); - private _requestOracle: RequestOracle; + private _requestOracle?: RequestOracle; private _cachedHeight: number; private _domNode: HTMLElement; private _message: HTMLDivElement; @@ -400,7 +400,7 @@ export class OutlinePanel extends ViewletPanel { this._message.innerText = escape(message); } - private static _createOutlineModel(model: ITextModel, disposables: IDisposable[]): Promise { + private static _createOutlineModel(model: ITextModel, disposables: IDisposable[]): Promise { let promise = createCancelablePromise(token => OutlineModel.create(model, token)); disposables.push({ dispose() { promise.cancel(); } }); return promise.catch(err => { @@ -411,7 +411,7 @@ export class OutlinePanel extends ViewletPanel { }); } - private async _doUpdate(editor: ICodeEditor, event: IModelContentChangedEvent): Promise { + private async _doUpdate(editor: ICodeEditor | undefined, event: IModelContentChangedEvent | undefined): Promise { dispose(this._editorDisposables); this._editorDisposables = new Array(); @@ -425,7 +425,7 @@ export class OutlinePanel extends ViewletPanel { this._treeStates.set(oldModel.textModel.uri.toString(), state); } - if (!editor || !DocumentSymbolProviderRegistry.has(editor.getModel())) { + if (!editor || !editor.hasModel() || !DocumentSymbolProviderRegistry.has(editor.getModel())) { return this._showMessage(localize('no-editor', "There are no editors open that can provide outline information.")); } @@ -438,12 +438,13 @@ export class OutlinePanel extends ViewletPanel { ); } - let newModel = await OutlinePanel._createOutlineModel(textModel, this._editorDisposables); + let createdModel = await OutlinePanel._createOutlineModel(textModel, this._editorDisposables); dispose(loadingMessage); - if (!newModel) { + if (!createdModel) { return; } + let newModel = createdModel; if (TreeElement.empty(newModel)) { return this._showMessage(localize('no-symbols', "No symbols found in document '{0}'", basename(textModel.uri))); } @@ -462,7 +463,7 @@ export class OutlinePanel extends ViewletPanel { if (newRatio <= oldRatio * 0.5 || newRatio >= oldRatio * 1.5) { let waitPromise = new Promise(resolve => { - let handle = setTimeout(() => { + let handle: any = setTimeout(() => { handle = undefined; resolve(true); }, 2000); @@ -598,7 +599,7 @@ export class OutlinePanel extends ViewletPanel { return; } let top = this._tree.getRelativeTop(item); - if (top < 0 || top > 1) { + if (typeof top === 'number' && (top < 0 || top > 1)) { // only when outside view port await this._tree.reveal(item, 0.5); } diff --git a/src/vs/workbench/contrib/output/electron-browser/output.contribution.ts b/src/vs/workbench/contrib/output/electron-browser/output.contribution.ts index e72863b7840..d759e524208 100644 --- a/src/vs/workbench/contrib/output/electron-browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/electron-browser/output.contribution.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; -import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { MenuId, MenuRegistry, SyncActionDescriptor, ILocalizedString } from 'vs/platform/actions/common/actions'; import { KeybindingsRegistry, IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; @@ -98,7 +98,7 @@ interface IActionDescriptor { handler: ICommandHandler; // ICommandUI - title: string; + title: ILocalizedString; category?: string; f1?: boolean; @@ -159,7 +159,7 @@ function registerAction(desc: IActionDescriptor) { // Define clear command, contribute to editor context menu registerAction({ id: 'editor.action.clearoutput', - title: nls.localize('clearOutput.label', "Clear Output"), + title: { value: nls.localize('clearOutput.label', "Clear Output"), original: 'Clear Output' }, menu: { menuId: MenuId.EditorContext, when: CONTEXT_IN_OUTPUT @@ -171,7 +171,7 @@ registerAction({ registerAction({ id: 'workbench.action.openActiveLogOutputFile', - title: nls.localize('openActiveLogOutputFile', "View: Open Active Log Output File"), + title: { value: nls.localize('openActiveLogOutputFile', "Open Active Log Output File"), original: 'Open Active Log Output File' }, menu: { menuId: MenuId.CommandPalette, when: CONTEXT_ACTIVE_LOG_OUTPUT diff --git a/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts index 5ccb0154105..e00f7328347 100644 --- a/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts @@ -476,6 +476,7 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: OpenFolderSettingsAction.ID, title: { value: `${category}: ${OpenFolderSettingsAction.LABEL}`, original: 'Preferences: Open Folder Settings' }, + category: nls.localize('preferencesCategory', "Prefernces") }, when: new RawContextKey('workbenchState', '').isEqualTo('workspace') }); @@ -487,6 +488,7 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: OpenWorkspaceSettingsAction.ID, title: { value: `${category}: ${OpenWorkspaceSettingsAction.LABEL}`, original: 'Preferences: Open Workspace Settings' }, + category: nls.localize('preferencesCategory', "Prefernces") }, when: new RawContextKey('workbenchState', '').notEqualsTo('empty') }); diff --git a/src/vs/workbench/contrib/search/browser/media/searchview.css b/src/vs/workbench/contrib/search/browser/media/searchview.css index 9cd664e1b18..ccbb55a6a85 100644 --- a/src/vs/workbench/contrib/search/browser/media/searchview.css +++ b/src/vs/workbench/contrib/search/browser/media/searchview.css @@ -51,6 +51,7 @@ .search-view .search-widget .monaco-findInput { display: inline-block; vertical-align: middle; + width: 100%; } .search-view .search-widget .replace-container { diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 52e381f537b..35d5f3a1547 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -634,7 +634,8 @@ export class SearchView extends Viewlet implements IViewlet, IPanel { { identityProvider, accessibilityProvider: this.instantiationService.createInstance(SearchAccessibilityProvider, this.viewModel), - dnd: this.instantiationService.createInstance(SearchDND) + dnd: this.instantiationService.createInstance(SearchDND), + multipleSelectionSupport: false })); this._register(this.tree.onContextMenu(e => this.onContextMenu(e))); @@ -1099,7 +1100,7 @@ export class SearchView extends Viewlet implements IViewlet, IPanel { if (relPath === '') { folderPath = `./${owningFolder.name}`; } else { - folderPath = `./${owningFolder.name}/${relativePath}`; + folderPath = `./${owningFolder.name}/${relPath}`; } } else { folderPath = resource.fsPath; // TODO rob: handle on-file URIs diff --git a/src/vs/workbench/contrib/search/browser/searchWidget.ts b/src/vs/workbench/contrib/search/browser/searchWidget.ts index 3010fb299d0..127e95673ae 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -169,7 +169,6 @@ export class SearchWidget extends Widget { } setWidth(width: number) { - this.searchInput.setWidth(width); this.replaceInput.width = width - 28; this.replaceInput.layout(); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.css b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.css index e04c75bc0e2..a4a092d8349 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.css +++ b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.css @@ -2,7 +2,3 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ - -.monaco-workbench .simple-find-part .monaco-inputbox > .wrapper > .input { - width: 100% !important; -} \ No newline at end of file diff --git a/src/vs/workbench/contrib/webview/electron-browser/webview-pre.js b/src/vs/workbench/contrib/webview/electron-browser/webview-pre.js index 389a4b89a2e..a239f09f03e 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webview-pre.js +++ b/src/vs/workbench/contrib/webview/electron-browser/webview-pre.js @@ -243,7 +243,7 @@ delete window.frameElement; `; - newDocument.head.prepend(defaultScript, newDocument.head.firstChild); + newDocument.head.prepend(defaultScript); } // apply default styles diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewEditor.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewEditor.ts index 3db8dc9bd78..b004ebbd6ea 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewEditor.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewEditor.ts @@ -222,6 +222,7 @@ export class WebviewEditor extends BaseWebviewEditor { { allowSvgs: true, extensionLocation: input.extensionLocation, + enableFindWidget: input.options.enableFindWidget }, {}); this._webview.mountTo(this._webviewContent); diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index 993ca09e1c2..1dd864c51c9 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -22,13 +22,13 @@ export interface WebviewOptions { readonly allowSvgs?: boolean; readonly useSameOriginForRoot?: boolean; readonly extensionLocation?: URI; + readonly enableFindWidget?: boolean; } export interface WebviewContentOptions { readonly allowScripts?: boolean; readonly svgWhiteList?: string[]; readonly localResourceRoots?: ReadonlyArray; - readonly disableFindView?: boolean; } interface IKeydownEvent { @@ -335,7 +335,7 @@ export class WebviewElement extends Disposable { this._send('devtools-opened'); })); - if (!this.options || !this.options.disableFindView) { + if (_options.enableFindWidget) { this._webviewFindWidget = this._register(instantiationService.createInstance(WebviewFindWidget, this)); } diff --git a/src/vs/workbench/electron-browser/actions/windowActions.ts b/src/vs/workbench/electron-browser/actions/windowActions.ts index 1c67d1881cd..4b03ec4c453 100644 --- a/src/vs/workbench/electron-browser/actions/windowActions.ts +++ b/src/vs/workbench/electron-browser/actions/windowActions.ts @@ -25,6 +25,8 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { IQuickInputService, IQuickPickItem, IQuickInputButton, IQuickPickSeparator, IKeyMods } from 'vs/platform/quickinput/common/quickInput'; import { getIconClasses } from 'vs/editor/common/services/getIconClasses'; import product from 'vs/platform/node/product'; +import { ICommandHandler } from 'vs/platform/commands/common/commands'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; export class CloseCurrentWindowAction extends Action { @@ -468,110 +470,26 @@ export class ShowAboutDialogAction extends Action { } } -export class NewWindowTab extends Action { +export const NewWindowTabHandler: ICommandHandler = function (accessor: ServicesAccessor) { + return accessor.get(IWindowsService).newWindowTab(); +}; - static readonly ID = 'workbench.action.newWindowTab'; - static readonly LABEL = nls.localize('newTab', "New Window Tab"); +export const ShowPreviousWindowTabHandler: ICommandHandler = function (accessor: ServicesAccessor) { + return accessor.get(IWindowsService).showPreviousWindowTab(); +}; - constructor( - _id: string, - _label: string, - @IWindowsService private readonly windowsService: IWindowsService - ) { - super(NewWindowTab.ID, NewWindowTab.LABEL); - } +export const ShowNextWindowTabHandler: ICommandHandler = function (accessor: ServicesAccessor) { + return accessor.get(IWindowsService).showNextWindowTab(); +}; - run(): Promise { - return this.windowsService.newWindowTab().then(() => true); - } -} +export const MoveWindowTabToNewWindowHandler: ICommandHandler = function (accessor: ServicesAccessor) { + return accessor.get(IWindowsService).moveWindowTabToNewWindow(); +}; -export class ShowPreviousWindowTab extends Action { +export const MergeWindowTabsHandlerHandler: ICommandHandler = function (accessor: ServicesAccessor) { + return accessor.get(IWindowsService).mergeAllWindowTabs(); +}; - static readonly ID = 'workbench.action.showPreviousWindowTab'; - static readonly LABEL = nls.localize('showPreviousTab', "Show Previous Window Tab"); - - constructor( - _id: string, - _label: string, - @IWindowsService private readonly windowsService: IWindowsService - ) { - super(ShowPreviousWindowTab.ID, ShowPreviousWindowTab.LABEL); - } - - run(): Promise { - return this.windowsService.showPreviousWindowTab().then(() => true); - } -} - -export class ShowNextWindowTab extends Action { - - static readonly ID = 'workbench.action.showNextWindowTab'; - static readonly LABEL = nls.localize('showNextWindowTab', "Show Next Window Tab"); - - constructor( - _id: string, - _label: string, - @IWindowsService private readonly windowsService: IWindowsService - ) { - super(ShowNextWindowTab.ID, ShowNextWindowTab.LABEL); - } - - run(): Promise { - return this.windowsService.showNextWindowTab().then(() => true); - } -} - -export class MoveWindowTabToNewWindow extends Action { - - static readonly ID = 'workbench.action.moveWindowTabToNewWindow'; - static readonly LABEL = nls.localize('moveWindowTabToNewWindow', "Move Window Tab to New Window"); - - constructor( - _id: string, - _label: string, - @IWindowsService private readonly windowsService: IWindowsService - ) { - super(MoveWindowTabToNewWindow.ID, MoveWindowTabToNewWindow.LABEL); - } - - run(): Promise { - return this.windowsService.moveWindowTabToNewWindow().then(() => true); - } -} - -export class MergeAllWindowTabs extends Action { - - static readonly ID = 'workbench.action.mergeAllWindowTabs'; - static readonly LABEL = nls.localize('mergeAllWindowTabs', "Merge All Windows"); - - constructor( - _id: string, - _label: string, - @IWindowsService private readonly windowsService: IWindowsService - ) { - super(MergeAllWindowTabs.ID, MergeAllWindowTabs.LABEL); - } - - run(): Promise { - return this.windowsService.mergeAllWindowTabs().then(() => true); - } -} - -export class ToggleWindowTabsBar extends Action { - - static readonly ID = 'workbench.action.toggleWindowTabsBar'; - static readonly LABEL = nls.localize('toggleWindowTabsBar', "Toggle Window Tabs Bar"); - - constructor( - _id: string, - _label: string, - @IWindowsService private readonly windowsService: IWindowsService - ) { - super(ToggleWindowTabsBar.ID, ToggleWindowTabsBar.LABEL); - } - - run(): Promise { - return this.windowsService.toggleWindowTabsBar().then(() => true); - } -} +export const ToggleWindowTabsBarHandler: ICommandHandler = function (accessor: ServicesAccessor) { + return accessor.get(IWindowsService).toggleWindowTabsBar(); +}; diff --git a/src/vs/workbench/electron-browser/main.contribution.ts b/src/vs/workbench/electron-browser/main.contribution.ts index fbd0dcd4a15..2b20a241748 100644 --- a/src/vs/workbench/electron-browser/main.contribution.ts +++ b/src/vs/workbench/electron-browser/main.contribution.ts @@ -12,8 +12,8 @@ import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/action import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform'; import { KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, OpenTipsAndTricksUrlAction, OpenTwitterUrlAction, OpenRequestFeatureUrlAction, OpenPrivacyStatementUrlAction, OpenLicenseUrlAction } from 'vs/workbench/electron-browser/actions/helpActions'; -import { ToggleSharedProcessAction, InspectContextKeysAction, ToggleScreencastModeAction } from 'vs/workbench/electron-browser/actions/developerActions'; -import { ShowAboutDialogAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, CloseCurrentWindowAction, SwitchWindow, NewWindowAction, QuickSwitchWindow, QuickOpenRecentAction, inRecentFilesPickerContextKey, OpenRecentAction } from 'vs/workbench/electron-browser/actions/windowActions'; +import { ToggleSharedProcessAction, InspectContextKeysAction, ToggleScreencastModeAction, ToggleDevToolsAction } from 'vs/workbench/electron-browser/actions/developerActions'; +import { ShowAboutDialogAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, CloseCurrentWindowAction, SwitchWindow, NewWindowAction, QuickSwitchWindow, QuickOpenRecentAction, inRecentFilesPickerContextKey, OpenRecentAction, ReloadWindowWithExtensionsDisabledAction, NewWindowTabHandler, ReloadWindowAction, ShowPreviousWindowTabHandler, ShowNextWindowTabHandler, MoveWindowTabToNewWindowHandler, MergeWindowTabsHandlerHandler, ToggleWindowTabsBarHandler } from 'vs/workbench/electron-browser/actions/windowActions'; import { AddRootFolderAction, GlobalRemoveRootFolderAction, OpenWorkspaceAction, SaveWorkspaceAsAction, OpenWorkspaceConfigFileAction, DuplicateWorkspaceInNewWindowAction, OpenFileFolderAction, OpenFileAction, OpenFolderAction, CloseWorkspaceAction } from 'vs/workbench/browser/actions/workspaceActions'; import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { inQuickOpenContext, getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen'; @@ -21,621 +21,675 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ADD_ROOT_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; -import { SupportsOpenFileFolderContext, SupportsWorkspacesContext, IsMacContext } from 'vs/platform/contextkey/common/contextkeys'; +import { SupportsWorkspacesContext, IsMacContext, HasMacNativeTabsContext, IsDevelopmentContext } from 'vs/platform/contextkey/common/contextkeys'; import { NoEditorsVisibleContext, SingleEditorGroupsContext } from 'vs/workbench/common/editor'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; +import { LogStorageAction } from 'vs/platform/storage/node/storageService'; -// Contribute Commands -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: 'workbench.action.closeWindow', // close the window when the last editor is closed by reusing the same keybinding - weight: KeybindingWeight.WorkbenchContrib, - when: ContextKeyExpr.and(NoEditorsVisibleContext, SingleEditorGroupsContext), - primary: KeyMod.CtrlCmd | KeyCode.KEY_W, - handler: accessor => { - const windowService = accessor.get(IWindowService); - windowService.closeWindow(); - } -}); +// Actions +(function registerActions(): void { + const registry = Registry.as(Extensions.WorkbenchActions); -const QUIT_ID = 'workbench.action.quit'; -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: QUIT_ID, - weight: KeybindingWeight.WorkbenchContrib, - handler(accessor: ServicesAccessor) { - const windowsService = accessor.get(IWindowsService); - windowsService.quit(); - }, - when: undefined, - primary: KeyMod.CtrlCmd | KeyCode.KEY_Q, - win: { primary: undefined } -}); + // Actions: File + (function registerFileActions(): void { + const fileCategory = nls.localize('file', "File"); -// Contribute Global Actions -const viewCategory = nls.localize('view', "View"); -const helpCategory = nls.localize('help', "Help"); -const fileCategory = nls.localize('file', "File"); -const workbenchActionsRegistry = Registry.as(Extensions.WorkbenchActions); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NewWindowAction, NewWindowAction.ID, NewWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_N }), 'New Window'); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseCurrentWindowAction, CloseCurrentWindowAction.ID, CloseCurrentWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W }), 'Close Window'); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SwitchWindow, SwitchWindow.ID, SwitchWindow.LABEL, { primary: 0, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_W } }), 'Switch Window...'); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(QuickSwitchWindow, QuickSwitchWindow.ID, QuickSwitchWindow.LABEL), 'Quick Switch Window...'); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenRecentAction, QuickOpenRecentAction.ID, QuickOpenRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory); - -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', fileCategory, SupportsOpenFileFolderContext); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory, SupportsOpenFileFolderContext.toNegated()); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', fileCategory, SupportsOpenFileFolderContext.toNegated()); - -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'File: Close Workspace', fileCategory); - -if (KeybindingsReferenceAction.AVAILABLE) { - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(KeybindingsReferenceAction, KeybindingsReferenceAction.ID, KeybindingsReferenceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_R) }), 'Help: Keyboard Shortcuts Reference', helpCategory); -} - -if (OpenDocumentationUrlAction.AVAILABLE) { - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenDocumentationUrlAction, OpenDocumentationUrlAction.ID, OpenDocumentationUrlAction.LABEL), 'Help: Documentation', helpCategory); -} - -if (OpenIntroductoryVideosUrlAction.AVAILABLE) { - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenIntroductoryVideosUrlAction, OpenIntroductoryVideosUrlAction.ID, OpenIntroductoryVideosUrlAction.LABEL), 'Help: Introductory Videos', helpCategory); -} - -if (OpenTipsAndTricksUrlAction.AVAILABLE) { - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenTipsAndTricksUrlAction, OpenTipsAndTricksUrlAction.ID, OpenTipsAndTricksUrlAction.LABEL), 'Help: Tips and Tricks', helpCategory); -} - -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenTwitterUrlAction, OpenTwitterUrlAction.ID, OpenTwitterUrlAction.LABEL), 'Help: Join Us on Twitter', helpCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenRequestFeatureUrlAction, OpenRequestFeatureUrlAction.ID, OpenRequestFeatureUrlAction.LABEL), 'Help: Search Feature Requests', helpCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenLicenseUrlAction, OpenLicenseUrlAction.ID, OpenLicenseUrlAction.LABEL), 'Help: View License', helpCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenPrivacyStatementUrlAction, OpenPrivacyStatementUrlAction.ID, OpenPrivacyStatementUrlAction.LABEL), 'Help: Privacy Statement', helpCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowAboutDialogAction, ShowAboutDialogAction.ID, ShowAboutDialogAction.LABEL), 'Help: About', helpCategory); - -workbenchActionsRegistry.registerWorkbenchAction( - new SyncActionDescriptor(ZoomInAction, ZoomInAction.ID, ZoomInAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.US_EQUAL, - secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_EQUAL, KeyMod.CtrlCmd | KeyCode.NUMPAD_ADD] - }), 'View: Zoom In', viewCategory); - -workbenchActionsRegistry.registerWorkbenchAction( - new SyncActionDescriptor(ZoomOutAction, ZoomOutAction.ID, ZoomOutAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, - secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_MINUS, KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT], - linux: { primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, secondary: [KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT] } - }), 'View: Zoom Out', viewCategory -); - -workbenchActionsRegistry.registerWorkbenchAction( - new SyncActionDescriptor(ZoomResetAction, ZoomResetAction.ID, ZoomResetAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.NUMPAD_0 - }), 'View: Reset Zoom', viewCategory -); - -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleFullScreenAction, ToggleFullScreenAction.ID, ToggleFullScreenAction.LABEL, { primary: KeyCode.F11, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_F } }), 'View: Toggle Full Screen', viewCategory); - -const workspacesCategory = nls.localize('workspaces', "Workspaces"); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory, SupportsWorkspacesContext); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRemoveRootFolderAction, GlobalRemoveRootFolderAction.ID, GlobalRemoveRootFolderAction.LABEL), 'Workspaces: Remove Folder from Workspace...', workspacesCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory, SupportsWorkspacesContext); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace As...', workspacesCategory, SupportsWorkspacesContext); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(DuplicateWorkspaceInNewWindowAction, DuplicateWorkspaceInNewWindowAction.ID, DuplicateWorkspaceInNewWindowAction.LABEL), 'Workspaces: Duplicate Workspace in New Window', workspacesCategory); - -CommandsRegistry.registerCommand(OpenWorkspaceConfigFileAction.ID, serviceAccessor => { - serviceAccessor.get(IInstantiationService).createInstance(OpenWorkspaceConfigFileAction, OpenWorkspaceConfigFileAction.ID, OpenWorkspaceConfigFileAction.LABEL).run(); -}); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { - command: { - id: OpenWorkspaceConfigFileAction.ID, - title: { value: `${workspacesCategory}: ${OpenWorkspaceConfigFileAction.LABEL}`, original: 'Workspaces: Open Workspace Configuration File' }, - }, - when: new RawContextKey('workbenchState', '').isEqualTo('workspace') -}); - -// Developer related actions -const developerCategory = nls.localize('developer', "Developer"); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSharedProcessAction, ToggleSharedProcessAction.ID, ToggleSharedProcessAction.LABEL), 'Developer: Toggle Shared Process', developerCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(InspectContextKeysAction, InspectContextKeysAction.ID, InspectContextKeysAction.LABEL), 'Developer: Inspect Context Keys', developerCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleScreencastModeAction, ToggleScreencastModeAction.ID, ToggleScreencastModeAction.LABEL), 'Developer: Toggle Mouse Clicks', developerCategory); - -const recentFilesPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExpr.has(inRecentFilesPickerContextKey)); - -const quickOpenNavigateNextInRecentFilesPickerId = 'workbench.action.quickOpenNavigateNextInRecentFilesPicker'; -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: quickOpenNavigateNextInRecentFilesPickerId, - weight: KeybindingWeight.WorkbenchContrib + 50, - handler: getQuickNavigateHandler(quickOpenNavigateNextInRecentFilesPickerId, true), - when: recentFilesPickerContext, - primary: KeyMod.CtrlCmd | KeyCode.KEY_R, - mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } -}); - -const quickOpenNavigatePreviousInRecentFilesPicker = 'workbench.action.quickOpenNavigatePreviousInRecentFilesPicker'; -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: quickOpenNavigatePreviousInRecentFilesPicker, - weight: KeybindingWeight.WorkbenchContrib + 50, - handler: getQuickNavigateHandler(quickOpenNavigatePreviousInRecentFilesPicker, false), - when: recentFilesPickerContext, - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_R, - mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_R } -}); - -// Menu registration - file menu - -MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '1_new', - command: { - id: NewWindowAction.ID, - title: nls.localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "New &&Window") - }, - order: 2 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '2_open', - command: { - id: OpenFileAction.ID, - title: nls.localize({ key: 'miOpenFile', comment: ['&& denotes a mnemonic'] }, "&&Open File...") - }, - order: 1, - when: SupportsOpenFileFolderContext.toNegated() -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '2_open', - command: { - id: OpenFolderAction.ID, - title: nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder...") - }, - order: 2, - when: SupportsOpenFileFolderContext.toNegated() -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '2_open', - command: { - id: OpenFileFolderAction.ID, - title: nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open...") - }, - order: 1, - when: SupportsOpenFileFolderContext -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '2_open', - command: { - id: OpenWorkspaceAction.ID, - title: nls.localize({ key: 'miOpenWorkspace', comment: ['&& denotes a mnemonic'] }, "Open Wor&&kspace...") - }, - order: 3, - when: SupportsWorkspacesContext -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - title: nls.localize({ key: 'miOpenRecent', comment: ['&& denotes a mnemonic'] }, "Open &&Recent"), - submenu: MenuId.MenubarRecentMenu, - group: '2_open', - order: 4 -}); - - -// More -MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, { - group: 'y_more', - command: { - id: OpenRecentAction.ID, - title: nls.localize({ key: 'miMore', comment: ['&& denotes a mnemonic'] }, "&&More...") - }, - order: 1 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '3_workspace', - command: { - id: ADD_ROOT_FOLDER_COMMAND_ID, - title: nls.localize({ key: 'miAddFolderToWorkspace', comment: ['&& denotes a mnemonic'] }, "A&&dd Folder to Workspace...") - }, - order: 1, - when: SupportsWorkspacesContext -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '3_workspace', - command: { - id: SaveWorkspaceAsAction.ID, - title: nls.localize('miSaveWorkspaceAs', "Save Workspace As...") - }, - order: 2, - when: SupportsWorkspacesContext -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - title: nls.localize({ key: 'miPreferences', comment: ['&& denotes a mnemonic'] }, "&&Preferences"), - submenu: MenuId.MenubarPreferencesMenu, - group: '5_autosave', - order: 2, - when: IsMacContext.toNegated() -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '6_close', - command: { - id: CloseWorkspaceAction.ID, - title: nls.localize({ key: 'miCloseFolder', comment: ['&& denotes a mnemonic'] }, "Close &&Folder"), - precondition: new RawContextKey('workspaceFolderCount', 0).notEqualsTo('0') - }, - order: 3, - when: new RawContextKey('workbenchState', '').notEqualsTo('workspace') -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '6_close', - command: { - id: CloseWorkspaceAction.ID, - title: nls.localize({ key: 'miCloseWorkspace', comment: ['&& denotes a mnemonic'] }, "Close &&Workspace") - }, - order: 3, - when: new RawContextKey('workbenchState', '').isEqualTo('workspace') -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '6_close', - command: { - id: CloseCurrentWindowAction.ID, - title: nls.localize({ key: 'miCloseWindow', comment: ['&& denotes a mnemonic'] }, "Clos&&e Window") - }, - order: 4 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: 'z_Exit', - command: { - id: QUIT_ID, - title: nls.localize({ key: 'miExit', comment: ['&& denotes a mnemonic'] }, "E&&xit") - }, - order: 1, - when: IsMacContext.toNegated() -}); - -// Appereance menu -MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { - group: '2_appearance', - title: nls.localize({ key: 'miAppearance', comment: ['&& denotes a mnemonic'] }, "&&Appearance"), - submenu: MenuId.MenubarAppearanceMenu, - order: 1 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '1_toggle_view', - command: { - id: ToggleFullScreenAction.ID, - title: nls.localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "Toggle &&Full Screen") - }, - order: 1 -}); - -// Zoom - -MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '3_zoom', - command: { - id: ZoomInAction.ID, - title: nls.localize({ key: 'miZoomIn', comment: ['&& denotes a mnemonic'] }, "&&Zoom In") - }, - order: 1 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '3_zoom', - command: { - id: ZoomOutAction.ID, - title: nls.localize({ key: 'miZoomOut', comment: ['&& denotes a mnemonic'] }, "&&Zoom Out") - }, - order: 2 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '3_zoom', - command: { - id: ZoomResetAction.ID, - title: nls.localize({ key: 'miZoomReset', comment: ['&& denotes a mnemonic'] }, "&&Reset Zoom") - }, - order: 3 -}); - -// Help - -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '1_welcome', - command: { - id: 'workbench.action.openDocumentationUrl', - title: nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation") - }, - order: 3 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '1_welcome', - command: { - id: 'update.showCurrentReleaseNotes', - title: nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes") - }, - order: 4 -}); - -// Reference -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '2_reference', - command: { - id: 'workbench.action.keybindingsReference', - title: nls.localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference") - }, - order: 1 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '2_reference', - command: { - id: 'workbench.action.openIntroductoryVideosUrl', - title: nls.localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos") - }, - order: 2 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '2_reference', - command: { - id: 'workbench.action.openTipsAndTricksUrl', - 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: 'workbench.action.openTwitterUrl', - title: nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join Us on Twitter") - }, - order: 1 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '3_feedback', - command: { - id: 'workbench.action.openRequestFeatureUrl', - title: nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests") - }, - order: 2 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '3_feedback', - command: { - id: 'workbench.action.openIssueReporter', - title: nls.localize({ key: 'miReportIssue', comment: ['&& denotes a mnemonic', 'Translate this to "Report Issue in English" in all languages please!'] }, "Report &&Issue") - }, - order: 3 -}); - -// Legal -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '4_legal', - command: { - id: 'workbench.action.openLicenseUrl', - title: nls.localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "View &&License") - }, - order: 1 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '4_legal', - command: { - id: 'workbench.action.openPrivacyStatementUrl', - title: nls.localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "Privac&&y Statement") - }, - order: 2 -}); - -// Tools -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '5_tools', - command: { - id: 'workbench.action.toggleDevTools', - title: nls.localize({ key: 'miToggleDevTools', comment: ['&& denotes a mnemonic'] }, "&&Toggle Developer Tools") - }, - order: 1 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '5_tools', - command: { - id: 'workbench.action.openProcessExplorer', - title: nls.localize({ key: 'miOpenProcessExplorerer', comment: ['&& denotes a mnemonic'] }, "Open &&Process Explorer") - }, - order: 2 -}); - -// About -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: 'z_about', - command: { - id: 'workbench.action.showAboutDialog', - title: nls.localize({ key: 'miAbout', comment: ['&& denotes a mnemonic'] }, "&&About") - }, - order: 1, - when: IsMacContext.toNegated() -}); - -// Configuration: Window -const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); -configurationRegistry.registerConfiguration({ - 'id': 'window', - 'order': 8, - 'title': nls.localize('windowConfigurationTitle', "Window"), - 'type': 'object', - 'properties': { - 'window.openFilesInNewWindow': { - 'type': 'string', - 'enum': ['on', 'off', 'default'], - 'enumDescriptions': [ - nls.localize('window.openFilesInNewWindow.on', "Files will open in a new window."), - nls.localize('window.openFilesInNewWindow.off', "Files will open in the window with the files' folder open or the last active window."), - isMacintosh ? - nls.localize('window.openFilesInNewWindow.defaultMac', "Files will open in the window with the files' folder open or the last active window unless opened via the Dock or from Finder.") : - nls.localize('window.openFilesInNewWindow.default', "Files will open in a new window unless picked from within the application (e.g. via the File menu).") - ], - 'default': 'off', - 'scope': ConfigurationScope.APPLICATION, - 'markdownDescription': - isMacintosh ? - nls.localize('openFilesInNewWindowMac', "Controls whether files should open in a new window. \nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") : - nls.localize('openFilesInNewWindow', "Controls whether files should open in a new window.\nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") - }, - 'window.openFoldersInNewWindow': { - 'type': 'string', - 'enum': ['on', 'off', 'default'], - 'enumDescriptions': [ - nls.localize('window.openFoldersInNewWindow.on', "Folders will open in a new window."), - nls.localize('window.openFoldersInNewWindow.off', "Folders will replace the last active window."), - nls.localize('window.openFoldersInNewWindow.default', "Folders will open in a new window unless a folder is picked from within the application (e.g. via the File menu).") - ], - 'default': 'default', - 'scope': ConfigurationScope.APPLICATION, - 'markdownDescription': nls.localize('openFoldersInNewWindow', "Controls whether folders should open in a new window or replace the last active window.\nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") - }, - 'window.openWithoutArgumentsInNewWindow': { - 'type': 'string', - 'enum': ['on', 'off'], - 'enumDescriptions': [ - nls.localize('window.openWithoutArgumentsInNewWindow.on', "Open a new empty window."), - nls.localize('window.openWithoutArgumentsInNewWindow.off', "Focus the last active running instance.") - ], - 'default': isMacintosh ? 'off' : 'on', - 'scope': ConfigurationScope.APPLICATION, - 'markdownDescription': nls.localize('openWithoutArgumentsInNewWindow', "Controls whether a new empty window should open when starting a second instance without arguments or if the last running instance should get focus.\nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") - }, - 'window.restoreWindows': { - 'type': 'string', - 'enum': ['all', 'folders', 'one', 'none'], - 'enumDescriptions': [ - nls.localize('window.reopenFolders.all', "Reopen all windows."), - nls.localize('window.reopenFolders.folders', "Reopen all folders. Empty workspaces will not be restored."), - nls.localize('window.reopenFolders.one', "Reopen the last active window."), - nls.localize('window.reopenFolders.none', "Never reopen a window. Always start with an empty one.") - ], - 'default': 'one', - 'scope': ConfigurationScope.APPLICATION, - 'description': nls.localize('restoreWindows', "Controls how windows are being reopened after a restart.") - }, - 'window.restoreFullscreen': { - 'type': 'boolean', - 'default': false, - 'scope': ConfigurationScope.APPLICATION, - 'description': nls.localize('restoreFullscreen', "Controls whether a window should restore to full screen mode if it was exited in full screen mode.") - }, - 'window.zoomLevel': { - 'type': 'number', - 'default': 0, - 'description': nls.localize('zoomLevel', "Adjust the zoom level of the window. The original size is 0 and each increment above (e.g. 1) or below (e.g. -1) represents zooming 20% larger or smaller. You can also enter decimals to adjust the zoom level with a finer granularity.") - }, - 'window.title': { - 'type': 'string', - 'default': isMacintosh ? '${activeEditorShort}${separator}${rootName}' : '${dirty}${activeEditorShort}${separator}${rootName}${separator}${appName}', - 'markdownDescription': nls.localize({ comment: ['This is the description for a setting. Values surrounded by parenthesis are not to be translated.'], key: 'title' }, - "Controls the window title based on the active editor. Variables are substituted based on the context:\n- `\${activeEditorShort}`: the file name (e.g. myFile.txt).\n- `\${activeEditorMedium}`: the path of the file relative to the workspace folder (e.g. myFolder/myFileFolder/myFile.txt).\n- `\${activeEditorLong}`: the full path of the file (e.g. /Users/Development/myFolder/myFileFolder/myFile.txt).\n- `\${activeFolderShort}`: the name of the folder the file is contained in (e.g. myFileFolder).\n- `\${activeFolderMedium}`: the path of the folder the file is contained in, relative to the workspace folder (e.g. myFolder/myFileFolder).\n- `\${activeFolderLong}`: the full path of the folder the file is contained in (e.g. /Users/Development/myFolder/myFileFolder).\n- `\${folderName}`: name of the workspace folder the file is contained in (e.g. myFolder).\n- `\${folderPath}`: file path of the workspace folder the file is contained in (e.g. /Users/Development/myFolder).\n- `\${rootName}`: name of the workspace (e.g. myFolder or myWorkspace).\n- `\${rootPath}`: file path of the workspace (e.g. /Users/Development/myWorkspace).\n- `\${appName}`: e.g. VS Code.\n- `\${dirty}`: a dirty indicator if the active editor is dirty.\n- `\${separator}`: a conditional separator (\" - \") that only shows when surrounded by variables with values or static text.") - }, - 'window.newWindowDimensions': { - 'type': 'string', - 'enum': ['default', 'inherit', 'maximized', 'fullscreen'], - 'enumDescriptions': [ - nls.localize('window.newWindowDimensions.default', "Open new windows in the center of the screen."), - nls.localize('window.newWindowDimensions.inherit', "Open new windows with same dimension as last active one."), - nls.localize('window.newWindowDimensions.maximized', "Open new windows maximized."), - nls.localize('window.newWindowDimensions.fullscreen', "Open new windows in full screen mode.") - ], - 'default': 'default', - 'scope': ConfigurationScope.APPLICATION, - 'description': nls.localize('newWindowDimensions', "Controls the dimensions of opening a new window when at least one window is already opened. Note that this setting does not have an impact on the first window that is opened. The first window will always restore the size and location as you left it before closing.") - }, - 'window.closeWhenEmpty': { - 'type': 'boolean', - 'default': false, - 'description': nls.localize('closeWhenEmpty', "Controls whether closing the last editor should also close the window. This setting only applies for windows that do not show folders.") - }, - 'window.menuBarVisibility': { - 'type': 'string', - 'enum': ['default', 'visible', 'toggle', 'hidden'], - 'enumDescriptions': [ - nls.localize('window.menuBarVisibility.default', "Menu is only hidden in full screen mode."), - nls.localize('window.menuBarVisibility.visible', "Menu is always visible even in full screen mode."), - nls.localize('window.menuBarVisibility.toggle', "Menu is hidden but can be displayed via Alt key."), - nls.localize('window.menuBarVisibility.hidden', "Menu is always hidden.") - ], - 'default': 'default', - 'scope': ConfigurationScope.APPLICATION, - 'description': nls.localize('menuBarVisibility', "Control the visibility of the menu bar. A setting of 'toggle' means that the menu bar is hidden and a single press of the Alt key will show it. By default, the menu bar will be visible, unless the window is full screen."), - 'included': isWindows || isLinux - }, - 'window.enableMenuBarMnemonics': { - 'type': 'boolean', - 'default': true, - 'scope': ConfigurationScope.APPLICATION, - 'description': nls.localize('enableMenuBarMnemonics', "If enabled, the main menus can be opened via Alt-key shortcuts. Disabling mnemonics allows to bind these Alt-key shortcuts to editor commands instead."), - 'included': isWindows || isLinux - }, - 'window.autoDetectHighContrast': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('autoDetectHighContrast', "If enabled, will automatically change to high contrast theme if Windows is using a high contrast theme, and to dark theme when switching away from a Windows high contrast theme."), - 'included': isWindows - }, - 'window.doubleClickIconToClose': { - 'type': 'boolean', - 'default': false, - 'scope': ConfigurationScope.APPLICATION, - 'markdownDescription': nls.localize('window.doubleClickIconToClose', "If enabled, double clicking the application icon in the title bar will close the window and the window cannot be dragged by the icon. This setting only has an effect when `#window.titleBarStyle#` is set to `custom`.") - }, - 'window.titleBarStyle': { - 'type': 'string', - 'enum': ['native', 'custom'], - 'default': isLinux ? 'native' : 'custom', - 'scope': ConfigurationScope.APPLICATION, - 'description': nls.localize('titleBarStyle', "Adjust the appearance of the window title bar. Changes require a full restart to apply.") - }, - 'window.nativeTabs': { - 'type': 'boolean', - 'default': false, - 'scope': ConfigurationScope.APPLICATION, - 'description': nls.localize('window.nativeTabs', "Enables macOS Sierra window tabs. Note that changes require a full restart to apply and that native tabs will disable a custom title bar style if configured."), - 'included': isMacintosh && parseFloat(os.release()) >= 16 // Minimum: macOS Sierra (10.12.x = darwin 16.x) - }, - 'window.nativeFullScreen': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('window.nativeFullScreen', "Controls if native full-screen should be used on macOS. Disable this option to prevent macOS from creating a new space when going full-screen."), - 'included': isMacintosh - }, - 'window.clickThroughInactive': { - 'type': 'boolean', - 'default': true, - 'scope': ConfigurationScope.APPLICATION, - 'description': nls.localize('window.clickThroughInactive', "If enabled, clicking on an inactive window will both activate the window and trigger the element under the mouse if it is clickable. If disabled, clicking anywhere on an inactive window will activate it only and a second click is required on the element."), - 'included': isMacintosh + if (isMacintosh) { + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', fileCategory); + } else { + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', fileCategory); } - } -}); -// Configuration: Telemetry -configurationRegistry.registerConfiguration({ - 'id': 'telemetry', - 'order': 110, - title: nls.localize('telemetryConfigurationTitle', "Telemetry"), - 'type': 'object', - 'properties': { - 'telemetry.enableCrashReporter': { - 'type': 'boolean', - 'description': nls.localize('telemetry.enableCrashReporting', "Enable crash reports to be sent to a Microsoft online service. \nThis option requires restart to take effect."), - 'default': true, - 'tags': ['usesOnlineServices'] + registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenRecentAction, QuickOpenRecentAction.ID, QuickOpenRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenRecentAction, OpenRecentAction.ID, OpenRecentAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', fileCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'File: Close Workspace', fileCategory); + + const recentFilesPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExpr.has(inRecentFilesPickerContextKey)); + + const quickOpenNavigateNextInRecentFilesPickerId = 'workbench.action.quickOpenNavigateNextInRecentFilesPicker'; + KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: quickOpenNavigateNextInRecentFilesPickerId, + weight: KeybindingWeight.WorkbenchContrib + 50, + handler: getQuickNavigateHandler(quickOpenNavigateNextInRecentFilesPickerId, true), + when: recentFilesPickerContext, + primary: KeyMod.CtrlCmd | KeyCode.KEY_R, + mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } + }); + + const quickOpenNavigatePreviousInRecentFilesPicker = 'workbench.action.quickOpenNavigatePreviousInRecentFilesPicker'; + KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: quickOpenNavigatePreviousInRecentFilesPicker, + weight: KeybindingWeight.WorkbenchContrib + 50, + handler: getQuickNavigateHandler(quickOpenNavigatePreviousInRecentFilesPicker, false), + when: recentFilesPickerContext, + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_R, + mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_R } + }); + })(); + + // Actions: View + (function registerViewActions(): void { + const viewCategory = nls.localize('view', "View"); + + registry.registerWorkbenchAction(new SyncActionDescriptor(ZoomInAction, ZoomInAction.ID, ZoomInAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.US_EQUAL, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_EQUAL, KeyMod.CtrlCmd | KeyCode.NUMPAD_ADD] }), 'View: Zoom In', viewCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(ZoomOutAction, ZoomOutAction.ID, ZoomOutAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_MINUS, KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT], linux: { primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, secondary: [KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT] } }), 'View: Zoom Out', viewCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(ZoomResetAction, ZoomResetAction.ID, ZoomResetAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.NUMPAD_0 }), 'View: Reset Zoom', viewCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleFullScreenAction, ToggleFullScreenAction.ID, ToggleFullScreenAction.LABEL, { primary: KeyCode.F11, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_F } }), 'View: Toggle Full Screen', viewCategory); + })(); + + // Actions: Window + (function registerWindowActions(): void { + registry.registerWorkbenchAction(new SyncActionDescriptor(NewWindowAction, NewWindowAction.ID, NewWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_N }), 'New Window'); + registry.registerWorkbenchAction(new SyncActionDescriptor(CloseCurrentWindowAction, CloseCurrentWindowAction.ID, CloseCurrentWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W }), 'Close Window'); + registry.registerWorkbenchAction(new SyncActionDescriptor(SwitchWindow, SwitchWindow.ID, SwitchWindow.LABEL, { primary: 0, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_W } }), 'Switch Window...'); + registry.registerWorkbenchAction(new SyncActionDescriptor(QuickSwitchWindow, QuickSwitchWindow.ID, QuickSwitchWindow.LABEL), 'Quick Switch Window...'); + + KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'workbench.action.closeWindow', // close the window when the last editor is closed by reusing the same keybinding + weight: KeybindingWeight.WorkbenchContrib, + when: ContextKeyExpr.and(NoEditorsVisibleContext, SingleEditorGroupsContext), + primary: KeyMod.CtrlCmd | KeyCode.KEY_W, + handler: accessor => { + const windowService = accessor.get(IWindowService); + windowService.closeWindow(); + } + }); + + KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'workbench.action.quit', + weight: KeybindingWeight.WorkbenchContrib, + handler(accessor: ServicesAccessor) { + const windowsService = accessor.get(IWindowsService); + windowsService.quit(); + }, + when: undefined, + primary: KeyMod.CtrlCmd | KeyCode.KEY_Q, + win: { primary: undefined } + }); + })(); + + // Actions: Workspaces + (function registerWorkspaceActions(): void { + const workspacesCategory = nls.localize('workspaces', "Workspaces"); + + registry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory, SupportsWorkspacesContext); + registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRemoveRootFolderAction, GlobalRemoveRootFolderAction.ID, GlobalRemoveRootFolderAction.LABEL), 'Workspaces: Remove Folder from Workspace...', workspacesCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory, SupportsWorkspacesContext); + registry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace As...', workspacesCategory, SupportsWorkspacesContext); + registry.registerWorkbenchAction(new SyncActionDescriptor(DuplicateWorkspaceInNewWindowAction, DuplicateWorkspaceInNewWindowAction.ID, DuplicateWorkspaceInNewWindowAction.LABEL), 'Workspaces: Duplicate Workspace in New Window', workspacesCategory); + + CommandsRegistry.registerCommand(OpenWorkspaceConfigFileAction.ID, serviceAccessor => { + serviceAccessor.get(IInstantiationService).createInstance(OpenWorkspaceConfigFileAction, OpenWorkspaceConfigFileAction.ID, OpenWorkspaceConfigFileAction.LABEL).run(); + }); + + MenuRegistry.appendMenuItem(MenuId.CommandPalette, { + command: { + id: OpenWorkspaceConfigFileAction.ID, + title: { value: `${workspacesCategory}: ${OpenWorkspaceConfigFileAction.LABEL}`, original: 'Workspaces: Open Workspace Configuration File' }, + }, + when: new RawContextKey('workbenchState', '').isEqualTo('workspace') + }); + })(); + + // Actions: macOS Native Tabs + (function registerMacOSNativeTabsActions(): void { + if (isMacintosh) { + [ + { handler: NewWindowTabHandler, id: 'workbench.action.newWindowTab', title: { value: nls.localize('newTab', "New Window Tab"), original: 'New Window Tab' } }, + { handler: ShowPreviousWindowTabHandler, id: 'workbench.action.showPreviousWindowTab', title: { value: nls.localize('showPreviousTab', "Show Previous Window Tab"), original: 'Show Previous Window Tab' } }, + { handler: ShowNextWindowTabHandler, id: 'workbench.action.showNextWindowTab', title: { value: nls.localize('showNextWindowTab', "Show Next Window Tab"), original: 'Show Next Window Tab' } }, + { handler: MoveWindowTabToNewWindowHandler, id: 'workbench.action.moveWindowTabToNewWindow', title: { value: nls.localize('moveWindowTabToNewWindow', "Move Window Tab to New Window"), original: 'Move Window Tab to New Window' } }, + { handler: MergeWindowTabsHandlerHandler, id: 'workbench.action.mergeAllWindowTabs', title: { value: nls.localize('mergeAllWindowTabs', "Merge All Windows"), original: 'Merge All Windows' } }, + { handler: ToggleWindowTabsBarHandler, id: 'workbench.action.toggleWindowTabsBar', title: { value: nls.localize('toggleWindowTabsBar', "Toggle Window Tabs Bar"), original: 'Toggle Window Tabs Bar' } } + ].forEach(command => { + CommandsRegistry.registerCommand(command.id, command.handler); + + MenuRegistry.appendMenuItem(MenuId.CommandPalette, { + command, + when: HasMacNativeTabsContext + }); + }); } + })(); + + // Actions: Developer + (function registerDeveloperActions(): void { + const developerCategory = nls.localize('developer', "Developer"); + registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSharedProcessAction, ToggleSharedProcessAction.ID, ToggleSharedProcessAction.LABEL), 'Developer: Toggle Shared Process', developerCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(InspectContextKeysAction, InspectContextKeysAction.ID, InspectContextKeysAction.LABEL), 'Developer: Inspect Context Keys', developerCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleScreencastModeAction, ToggleScreencastModeAction.ID, ToggleScreencastModeAction.LABEL), 'Developer: Toggle Mouse Clicks', developerCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowWithExtensionsDisabledAction, ReloadWindowWithExtensionsDisabledAction.ID, ReloadWindowWithExtensionsDisabledAction.LABEL), 'Developer: Reload Window Without Extensions', developerCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(LogStorageAction, LogStorageAction.ID, LogStorageAction.LABEL), 'Developer: Log Storage', developerCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL), 'Developer: Reload Window', developerCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleDevToolsAction, ToggleDevToolsAction.ID, ToggleDevToolsAction.LABEL), 'Developer: Toggle Developer Tools', developerCategory); + + KeybindingsRegistry.registerKeybindingRule({ + id: ReloadWindowAction.ID, + weight: KeybindingWeight.WorkbenchContrib + 50, + when: IsDevelopmentContext, + primary: KeyMod.CtrlCmd | KeyCode.KEY_R + }); + + KeybindingsRegistry.registerKeybindingRule({ + id: ToggleDevToolsAction.ID, + weight: KeybindingWeight.WorkbenchContrib + 50, + when: IsDevelopmentContext, + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I, + mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_I } + }); + })(); + + // Actions: help + (function registerHelpActions(): void { + const helpCategory = nls.localize('help', "Help"); + + if (KeybindingsReferenceAction.AVAILABLE) { + registry.registerWorkbenchAction(new SyncActionDescriptor(KeybindingsReferenceAction, KeybindingsReferenceAction.ID, KeybindingsReferenceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_R) }), 'Help: Keyboard Shortcuts Reference', helpCategory); + } + + if (OpenDocumentationUrlAction.AVAILABLE) { + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDocumentationUrlAction, OpenDocumentationUrlAction.ID, OpenDocumentationUrlAction.LABEL), 'Help: Documentation', helpCategory); + } + + if (OpenIntroductoryVideosUrlAction.AVAILABLE) { + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenIntroductoryVideosUrlAction, OpenIntroductoryVideosUrlAction.ID, OpenIntroductoryVideosUrlAction.LABEL), 'Help: Introductory Videos', helpCategory); + } + + if (OpenTipsAndTricksUrlAction.AVAILABLE) { + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenTipsAndTricksUrlAction, OpenTipsAndTricksUrlAction.ID, OpenTipsAndTricksUrlAction.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); + registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAboutDialogAction, ShowAboutDialogAction.ID, ShowAboutDialogAction.LABEL), 'Help: About', helpCategory); + })(); +})(); + +// Menu +(function registerMenu(): void { + MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + group: '1_new', + command: { + id: NewWindowAction.ID, + title: nls.localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "New &&Window") + }, + order: 2 + }); + + if (isMacintosh) { + MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + group: '2_open', + command: { + id: OpenFileFolderAction.ID, + title: nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open...") + }, + order: 1 + }); + } else { + MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + group: '2_open', + command: { + id: OpenFileAction.ID, + title: nls.localize({ key: 'miOpenFile', comment: ['&& denotes a mnemonic'] }, "&&Open File...") + }, + order: 1 + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + group: '2_open', + command: { + id: OpenFolderAction.ID, + title: nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder...") + }, + order: 2 + }); } -}); \ No newline at end of file + + MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + group: '2_open', + command: { + id: OpenWorkspaceAction.ID, + title: nls.localize({ key: 'miOpenWorkspace', comment: ['&& denotes a mnemonic'] }, "Open Wor&&kspace...") + }, + order: 3, + when: SupportsWorkspacesContext + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + title: nls.localize({ key: 'miOpenRecent', comment: ['&& denotes a mnemonic'] }, "Open &&Recent"), + submenu: MenuId.MenubarRecentMenu, + group: '2_open', + order: 4 + }); + + // More + MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, { + group: 'y_more', + command: { + id: OpenRecentAction.ID, + title: nls.localize({ key: 'miMore', comment: ['&& denotes a mnemonic'] }, "&&More...") + }, + order: 1 + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + group: '3_workspace', + command: { + id: ADD_ROOT_FOLDER_COMMAND_ID, + title: nls.localize({ key: 'miAddFolderToWorkspace', comment: ['&& denotes a mnemonic'] }, "A&&dd Folder to Workspace...") + }, + order: 1, + when: SupportsWorkspacesContext + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + group: '3_workspace', + command: { + id: SaveWorkspaceAsAction.ID, + title: nls.localize('miSaveWorkspaceAs', "Save Workspace As...") + }, + order: 2, + when: SupportsWorkspacesContext + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + title: nls.localize({ key: 'miPreferences', comment: ['&& denotes a mnemonic'] }, "&&Preferences"), + submenu: MenuId.MenubarPreferencesMenu, + group: '5_autosave', + order: 2, + when: IsMacContext.toNegated() + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + group: '6_close', + command: { + id: CloseWorkspaceAction.ID, + title: nls.localize({ key: 'miCloseFolder', comment: ['&& denotes a mnemonic'] }, "Close &&Folder"), + precondition: new RawContextKey('workspaceFolderCount', 0).notEqualsTo('0') + }, + order: 3, + when: new RawContextKey('workbenchState', '').notEqualsTo('workspace') + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + group: '6_close', + command: { + id: CloseWorkspaceAction.ID, + title: nls.localize({ key: 'miCloseWorkspace', comment: ['&& denotes a mnemonic'] }, "Close &&Workspace") + }, + order: 3, + when: new RawContextKey('workbenchState', '').isEqualTo('workspace') + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + group: '6_close', + command: { + id: CloseCurrentWindowAction.ID, + title: nls.localize({ key: 'miCloseWindow', comment: ['&& denotes a mnemonic'] }, "Clos&&e Window") + }, + order: 4 + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + group: 'z_Exit', + command: { + id: 'workbench.action.quit', + title: nls.localize({ key: 'miExit', comment: ['&& denotes a mnemonic'] }, "E&&xit") + }, + order: 1, + when: IsMacContext.toNegated() + }); + + // Appereance menu + MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { + group: '2_appearance', + title: nls.localize({ key: 'miAppearance', comment: ['&& denotes a mnemonic'] }, "&&Appearance"), + submenu: MenuId.MenubarAppearanceMenu, + order: 1 + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { + group: '1_toggle_view', + command: { + id: ToggleFullScreenAction.ID, + title: nls.localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "Toggle &&Full Screen") + }, + order: 1 + }); + + // Zoom + + MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { + group: '3_zoom', + command: { + id: ZoomInAction.ID, + title: nls.localize({ key: 'miZoomIn', comment: ['&& denotes a mnemonic'] }, "&&Zoom In") + }, + order: 1 + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { + group: '3_zoom', + command: { + id: ZoomOutAction.ID, + title: nls.localize({ key: 'miZoomOut', comment: ['&& denotes a mnemonic'] }, "&&Zoom Out") + }, + order: 2 + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { + group: '3_zoom', + command: { + id: ZoomResetAction.ID, + title: nls.localize({ key: 'miZoomReset', comment: ['&& denotes a mnemonic'] }, "&&Reset Zoom") + }, + order: 3 + }); + + // Help + + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '1_welcome', + command: { + id: 'workbench.action.openDocumentationUrl', + title: nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation") + }, + order: 3 + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '1_welcome', + command: { + id: 'update.showCurrentReleaseNotes', + title: nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes") + }, + order: 4 + }); + + // Reference + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '2_reference', + command: { + id: 'workbench.action.keybindingsReference', + title: nls.localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference") + }, + order: 1 + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '2_reference', + command: { + id: 'workbench.action.openIntroductoryVideosUrl', + title: nls.localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos") + }, + order: 2 + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '2_reference', + command: { + id: 'workbench.action.openTipsAndTricksUrl', + 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: 'workbench.action.openTwitterUrl', + title: nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join Us on Twitter") + }, + order: 1 + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '3_feedback', + command: { + id: 'workbench.action.openRequestFeatureUrl', + title: nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests") + }, + order: 2 + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '3_feedback', + command: { + id: 'workbench.action.openIssueReporter', + title: nls.localize({ key: 'miReportIssue', comment: ['&& denotes a mnemonic', 'Translate this to "Report Issue in English" in all languages please!'] }, "Report &&Issue") + }, + order: 3 + }); + + // Legal + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '4_legal', + command: { + id: 'workbench.action.openLicenseUrl', + title: nls.localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "View &&License") + }, + order: 1 + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '4_legal', + command: { + id: 'workbench.action.openPrivacyStatementUrl', + title: nls.localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "Privac&&y Statement") + }, + order: 2 + }); + + // Tools + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '5_tools', + command: { + id: 'workbench.action.toggleDevTools', + title: nls.localize({ key: 'miToggleDevTools', comment: ['&& denotes a mnemonic'] }, "&&Toggle Developer Tools") + }, + order: 1 + }); + + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '5_tools', + command: { + id: 'workbench.action.openProcessExplorer', + title: nls.localize({ key: 'miOpenProcessExplorerer', comment: ['&& denotes a mnemonic'] }, "Open &&Process Explorer") + }, + order: 2 + }); + + // About + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: 'z_about', + command: { + id: 'workbench.action.showAboutDialog', + title: nls.localize({ key: 'miAbout', comment: ['&& denotes a mnemonic'] }, "&&About") + }, + order: 1, + when: IsMacContext.toNegated() + }); +})(); + +// Configuration +(function registerConfiguration(): void { + const registry = Registry.as(ConfigurationExtensions.Configuration); + + // Window + registry.registerConfiguration({ + 'id': 'window', + 'order': 8, + 'title': nls.localize('windowConfigurationTitle', "Window"), + 'type': 'object', + 'properties': { + 'window.openFilesInNewWindow': { + 'type': 'string', + 'enum': ['on', 'off', 'default'], + 'enumDescriptions': [ + nls.localize('window.openFilesInNewWindow.on', "Files will open in a new window."), + nls.localize('window.openFilesInNewWindow.off', "Files will open in the window with the files' folder open or the last active window."), + isMacintosh ? + nls.localize('window.openFilesInNewWindow.defaultMac', "Files will open in the window with the files' folder open or the last active window unless opened via the Dock or from Finder.") : + nls.localize('window.openFilesInNewWindow.default', "Files will open in a new window unless picked from within the application (e.g. via the File menu).") + ], + 'default': 'off', + 'scope': ConfigurationScope.APPLICATION, + 'markdownDescription': + isMacintosh ? + nls.localize('openFilesInNewWindowMac', "Controls whether files should open in a new window. \nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") : + nls.localize('openFilesInNewWindow', "Controls whether files should open in a new window.\nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") + }, + 'window.openFoldersInNewWindow': { + 'type': 'string', + 'enum': ['on', 'off', 'default'], + 'enumDescriptions': [ + nls.localize('window.openFoldersInNewWindow.on', "Folders will open in a new window."), + nls.localize('window.openFoldersInNewWindow.off', "Folders will replace the last active window."), + nls.localize('window.openFoldersInNewWindow.default', "Folders will open in a new window unless a folder is picked from within the application (e.g. via the File menu).") + ], + 'default': 'default', + 'scope': ConfigurationScope.APPLICATION, + 'markdownDescription': nls.localize('openFoldersInNewWindow', "Controls whether folders should open in a new window or replace the last active window.\nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") + }, + 'window.openWithoutArgumentsInNewWindow': { + 'type': 'string', + 'enum': ['on', 'off'], + 'enumDescriptions': [ + nls.localize('window.openWithoutArgumentsInNewWindow.on', "Open a new empty window."), + nls.localize('window.openWithoutArgumentsInNewWindow.off', "Focus the last active running instance.") + ], + 'default': isMacintosh ? 'off' : 'on', + 'scope': ConfigurationScope.APPLICATION, + 'markdownDescription': nls.localize('openWithoutArgumentsInNewWindow', "Controls whether a new empty window should open when starting a second instance without arguments or if the last running instance should get focus.\nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") + }, + 'window.restoreWindows': { + 'type': 'string', + 'enum': ['all', 'folders', 'one', 'none'], + 'enumDescriptions': [ + nls.localize('window.reopenFolders.all', "Reopen all windows."), + nls.localize('window.reopenFolders.folders', "Reopen all folders. Empty workspaces will not be restored."), + nls.localize('window.reopenFolders.one', "Reopen the last active window."), + nls.localize('window.reopenFolders.none', "Never reopen a window. Always start with an empty one.") + ], + 'default': 'one', + 'scope': ConfigurationScope.APPLICATION, + 'description': nls.localize('restoreWindows', "Controls how windows are being reopened after a restart.") + }, + 'window.restoreFullscreen': { + 'type': 'boolean', + 'default': false, + 'scope': ConfigurationScope.APPLICATION, + 'description': nls.localize('restoreFullscreen', "Controls whether a window should restore to full screen mode if it was exited in full screen mode.") + }, + 'window.zoomLevel': { + 'type': 'number', + 'default': 0, + 'description': nls.localize('zoomLevel', "Adjust the zoom level of the window. The original size is 0 and each increment above (e.g. 1) or below (e.g. -1) represents zooming 20% larger or smaller. You can also enter decimals to adjust the zoom level with a finer granularity.") + }, + 'window.title': { + 'type': 'string', + 'default': isMacintosh ? '${activeEditorShort}${separator}${rootName}' : '${dirty}${activeEditorShort}${separator}${rootName}${separator}${appName}', + 'markdownDescription': nls.localize({ comment: ['This is the description for a setting. Values surrounded by parenthesis are not to be translated.'], key: 'title' }, + "Controls the window title based on the active editor. Variables are substituted based on the context:\n- `\${activeEditorShort}`: the file name (e.g. myFile.txt).\n- `\${activeEditorMedium}`: the path of the file relative to the workspace folder (e.g. myFolder/myFileFolder/myFile.txt).\n- `\${activeEditorLong}`: the full path of the file (e.g. /Users/Development/myFolder/myFileFolder/myFile.txt).\n- `\${activeFolderShort}`: the name of the folder the file is contained in (e.g. myFileFolder).\n- `\${activeFolderMedium}`: the path of the folder the file is contained in, relative to the workspace folder (e.g. myFolder/myFileFolder).\n- `\${activeFolderLong}`: the full path of the folder the file is contained in (e.g. /Users/Development/myFolder/myFileFolder).\n- `\${folderName}`: name of the workspace folder the file is contained in (e.g. myFolder).\n- `\${folderPath}`: file path of the workspace folder the file is contained in (e.g. /Users/Development/myFolder).\n- `\${rootName}`: name of the workspace (e.g. myFolder or myWorkspace).\n- `\${rootPath}`: file path of the workspace (e.g. /Users/Development/myWorkspace).\n- `\${appName}`: e.g. VS Code.\n- `\${dirty}`: a dirty indicator if the active editor is dirty.\n- `\${separator}`: a conditional separator (\" - \") that only shows when surrounded by variables with values or static text.") + }, + 'window.newWindowDimensions': { + 'type': 'string', + 'enum': ['default', 'inherit', 'maximized', 'fullscreen'], + 'enumDescriptions': [ + nls.localize('window.newWindowDimensions.default', "Open new windows in the center of the screen."), + nls.localize('window.newWindowDimensions.inherit', "Open new windows with same dimension as last active one."), + nls.localize('window.newWindowDimensions.maximized', "Open new windows maximized."), + nls.localize('window.newWindowDimensions.fullscreen', "Open new windows in full screen mode.") + ], + 'default': 'default', + 'scope': ConfigurationScope.APPLICATION, + 'description': nls.localize('newWindowDimensions', "Controls the dimensions of opening a new window when at least one window is already opened. Note that this setting does not have an impact on the first window that is opened. The first window will always restore the size and location as you left it before closing.") + }, + 'window.closeWhenEmpty': { + 'type': 'boolean', + 'default': false, + 'description': nls.localize('closeWhenEmpty', "Controls whether closing the last editor should also close the window. This setting only applies for windows that do not show folders.") + }, + 'window.menuBarVisibility': { + 'type': 'string', + 'enum': ['default', 'visible', 'toggle', 'hidden'], + 'enumDescriptions': [ + nls.localize('window.menuBarVisibility.default', "Menu is only hidden in full screen mode."), + nls.localize('window.menuBarVisibility.visible', "Menu is always visible even in full screen mode."), + nls.localize('window.menuBarVisibility.toggle', "Menu is hidden but can be displayed via Alt key."), + nls.localize('window.menuBarVisibility.hidden', "Menu is always hidden.") + ], + 'default': 'default', + 'scope': ConfigurationScope.APPLICATION, + 'description': nls.localize('menuBarVisibility', "Control the visibility of the menu bar. A setting of 'toggle' means that the menu bar is hidden and a single press of the Alt key will show it. By default, the menu bar will be visible, unless the window is full screen."), + 'included': isWindows || isLinux + }, + 'window.enableMenuBarMnemonics': { + 'type': 'boolean', + 'default': true, + 'scope': ConfigurationScope.APPLICATION, + 'description': nls.localize('enableMenuBarMnemonics', "If enabled, the main menus can be opened via Alt-key shortcuts. Disabling mnemonics allows to bind these Alt-key shortcuts to editor commands instead."), + 'included': isWindows || isLinux + }, + 'window.autoDetectHighContrast': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('autoDetectHighContrast', "If enabled, will automatically change to high contrast theme if Windows is using a high contrast theme, and to dark theme when switching away from a Windows high contrast theme."), + 'included': isWindows + }, + 'window.doubleClickIconToClose': { + 'type': 'boolean', + 'default': false, + 'scope': ConfigurationScope.APPLICATION, + 'markdownDescription': nls.localize('window.doubleClickIconToClose', "If enabled, double clicking the application icon in the title bar will close the window and the window cannot be dragged by the icon. This setting only has an effect when `#window.titleBarStyle#` is set to `custom`.") + }, + 'window.titleBarStyle': { + 'type': 'string', + 'enum': ['native', 'custom'], + 'default': isLinux ? 'native' : 'custom', + 'scope': ConfigurationScope.APPLICATION, + 'description': nls.localize('titleBarStyle', "Adjust the appearance of the window title bar. On Linux and Windows, this setting also affects the application and context menu appearances. Changes require a full restart to apply.") + }, + 'window.nativeTabs': { + 'type': 'boolean', + 'default': false, + 'scope': ConfigurationScope.APPLICATION, + 'description': nls.localize('window.nativeTabs', "Enables macOS Sierra window tabs. Note that changes require a full restart to apply and that native tabs will disable a custom title bar style if configured."), + 'included': isMacintosh && parseFloat(os.release()) >= 16 // Minimum: macOS Sierra (10.12.x = darwin 16.x) + }, + 'window.nativeFullScreen': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('window.nativeFullScreen', "Controls if native full-screen should be used on macOS. Disable this option to prevent macOS from creating a new space when going full-screen."), + 'included': isMacintosh + }, + 'window.clickThroughInactive': { + 'type': 'boolean', + 'default': true, + 'scope': ConfigurationScope.APPLICATION, + 'description': nls.localize('window.clickThroughInactive', "If enabled, clicking on an inactive window will both activate the window and trigger the element under the mouse if it is clickable. If disabled, clicking anywhere on an inactive window will activate it only and a second click is required on the element."), + 'included': isMacintosh + } + } + }); + + // Telemetry + registry.registerConfiguration({ + 'id': 'telemetry', + 'order': 110, + title: nls.localize('telemetryConfigurationTitle', "Telemetry"), + 'type': 'object', + 'properties': { + 'telemetry.enableCrashReporter': { + 'type': 'boolean', + 'description': nls.localize('telemetry.enableCrashReporting', "Enable crash reports to be sent to a Microsoft online service. \nThis option requires restart to take effect."), + 'default': true, + 'tags': ['usesOnlineServices'] + } + } + }); +})(); \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/main.ts b/src/vs/workbench/electron-browser/main.ts index 74d374d483b..668a520d9e9 100644 --- a/src/vs/workbench/electron-browser/main.ts +++ b/src/vs/workbench/electron-browser/main.ts @@ -303,8 +303,8 @@ export class CodeWindow extends Disposable { }); } - private createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IEnvironmentService, logService: ILogService, mainProcessClient: ElectronIPCClient): Promise { - const globalStorageDatabase = new GlobalStorageDatabaseChannelClient(mainProcessClient.getChannel('storage')); + private createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IEnvironmentService, logService: ILogService, electronMainClient: ElectronIPCClient): Promise { + const globalStorageDatabase = new GlobalStorageDatabaseChannelClient(electronMainClient.getChannel('storage')); const storageService = new StorageService(globalStorageDatabase, logService, environmentService); return storageService.initialize(payload).then(() => storageService, error => { @@ -315,11 +315,11 @@ export class CodeWindow extends Disposable { }); } - private createLogService(mainProcessClient: ElectronIPCClient, environmentService: IEnvironmentService): ILogService { + private createLogService(electronMainClient: ElectronIPCClient, environmentService: IEnvironmentService): ILogService { const spdlogService = createSpdLogService(`renderer${this.configuration.windowId}`, this.configuration.logLevel, environmentService.logsPath); const consoleLogService = new ConsoleLogService(this.configuration.logLevel); const logService = new MultiplexLogService([consoleLogService, spdlogService]); - const logLevelClient = new LogLevelSetterChannelClient(mainProcessClient.getChannel('loglevel')); + const logLevelClient = new LogLevelSetterChannelClient(electronMainClient.getChannel('loglevel')); return new FollowerLogService(logLevelClient, logService); } diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 63267bb3061..2390b8d66dd 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -5,10 +5,9 @@ import 'vs/workbench/browser/style'; -import { localize } from 'vs/nls'; import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; -import { EventType, addDisposableListener, addClasses, scheduleAtNextAnimationFrame, addClass, removeClass, trackFocus, isAncestor, getClientArea, position, size } from 'vs/base/browser/dom'; +import { EventType, addDisposableListener, addClasses, scheduleAtNextAnimationFrame, addClass, removeClass, trackFocus, isAncestor, getClientArea, position, size, removeClasses } from 'vs/base/browser/dom'; import { RunOnceScheduler, runWhenIdle } from 'vs/base/common/async'; import { getZoomLevel, onDidChangeFullscreen, isFullscreen, getZoomFactor } from 'vs/base/browser/browser'; import { mark } from 'vs/base/common/performance'; @@ -62,19 +61,17 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle import { LifecyclePhase, StartupKind, ILifecycleService, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle'; import { IWindowService, IWindowConfiguration, IPath, MenuBarVisibility, getTitleBarStyle, IWindowsService } from 'vs/platform/windows/common/windows'; import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; -import { IMenuService, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { IMenuService } from 'vs/platform/actions/common/actions'; import { MenuService } from 'vs/platform/actions/common/menuService'; import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; -import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService'; import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; import { ActivityService } from 'vs/workbench/services/activity/browser/activityService'; import { URI } from 'vs/base/common/uri'; import { IListService, ListService } from 'vs/platform/list/browser/listService'; -import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, SupportsOpenFileFolderContext, SupportsWorkspacesContext } from 'vs/platform/contextkey/common/contextkeys'; +import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, SupportsOpenFileFolderContext, SupportsWorkspacesContext, IsDevelopmentContext, HasMacNativeTabsContext } from 'vs/platform/contextkey/common/contextkeys'; import { IViewsService } from 'vs/workbench/common/views'; import { ViewsService } from 'vs/workbench/browser/parts/views/views'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -137,16 +134,18 @@ import { IIntegrityService } from 'vs/workbench/services/integrity/common/integr import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; import { HistoryService } from 'vs/workbench/services/history/browser/history'; import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; +import { WorkbenchThemeService } from 'vs/workbench/services/themes/browser/workbenchThemeService'; -// import@node +// todo@move import product from 'vs/platform/node/product'; import pkg from 'vs/platform/node/package'; + +// import@node import { BackupFileService, InMemoryBackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; import { WorkspaceService, DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationService'; import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService'; import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService'; import { getDelayedChannel } from 'vs/base/parts/ipc/node/ipc'; -import { LogStorageAction } from 'vs/platform/storage/node/storageService'; import { HashService } from 'vs/workbench/services/hash/node/hashService'; import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net'; import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc'; @@ -172,11 +171,8 @@ import { WorkbenchKeybindingService } from 'vs/workbench/services/keybinding/ele import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService'; import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService'; import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService'; -import { ToggleDevToolsAction } from 'vs/workbench/electron-browser/actions/developerActions'; import { IExtensionUrlHandler, ExtensionUrlHandler } from 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler'; -import { WorkbenchThemeService } from 'vs/workbench/services/themes/browser/workbenchThemeService'; import { DialogService, FileDialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService'; -import { ShowPreviousWindowTab, MoveWindowTabToNewWindow, MergeAllWindowTabs, ShowNextWindowTab, ToggleWindowTabsBar, NewWindowTab, OpenRecentAction, ReloadWindowAction, ReloadWindowWithExtensionsDisabledAction } from 'vs/workbench/electron-browser/actions/windowActions'; import { IBroadcastService, BroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService'; import { WindowService } from 'vs/platform/windows/electron-browser/windowService'; import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-browser/remoteAuthorityResolverService'; @@ -418,9 +414,6 @@ export class Workbench extends Disposable implements IPartService { // Create Workbench Container this.createWorkbench(); - // Install some global actions - this.createGlobalActions(); - // Services this.initServices(this.serviceCollection); @@ -459,30 +452,10 @@ export class Workbench extends Disposable implements IPartService { this.workbench = document.createElement('div'); this.workbench.id = Identifiers.WORKBENCH_CONTAINER; - addClasses(this.workbench, 'monaco-workbench', isWindows ? 'windows' : isLinux ? 'linux' : 'mac'); - } + const platformClass = isWindows ? 'windows' : isLinux ? 'linux' : 'mac'; - private createGlobalActions(): void { - const isDeveloping = !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment; - - // Actions registered here to adjust for developing vs built workbench - const registry = Registry.as(Extensions.WorkbenchActions); - registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL, isDeveloping ? { primary: KeyMod.CtrlCmd | KeyCode.KEY_R } : undefined), 'Reload Window'); - registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleDevToolsAction, ToggleDevToolsAction.ID, ToggleDevToolsAction.LABEL, isDeveloping ? { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_I } } : undefined), 'Developer: Toggle Developer Tools', localize('developer', "Developer")); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenRecentAction, OpenRecentAction.ID, OpenRecentAction.LABEL, { primary: isDeveloping ? null : KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', localize('file', "File")); - registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowWithExtensionsDisabledAction, ReloadWindowWithExtensionsDisabledAction.ID, ReloadWindowWithExtensionsDisabledAction.LABEL), 'Reload Window Without Extensions'); - registry.registerWorkbenchAction(new SyncActionDescriptor(LogStorageAction, LogStorageAction.ID, LogStorageAction.LABEL), 'Developer: Log Storage', localize('developer', "Developer")); - - // Actions for macOS native tabs management (only when enabled) - const windowConfig = this.configurationService.getValue(); - if (windowConfig && windowConfig.window && windowConfig.window.nativeTabs) { - registry.registerWorkbenchAction(new SyncActionDescriptor(NewWindowTab, NewWindowTab.ID, NewWindowTab.LABEL), 'New Window Tab'); - registry.registerWorkbenchAction(new SyncActionDescriptor(ShowPreviousWindowTab, ShowPreviousWindowTab.ID, ShowPreviousWindowTab.LABEL), 'Show Previous Window Tab'); - registry.registerWorkbenchAction(new SyncActionDescriptor(ShowNextWindowTab, ShowNextWindowTab.ID, ShowNextWindowTab.LABEL), 'Show Next Window Tab'); - registry.registerWorkbenchAction(new SyncActionDescriptor(MoveWindowTabToNewWindow, MoveWindowTabToNewWindow.ID, MoveWindowTabToNewWindow.LABEL), 'Move Window Tab to New Window'); - registry.registerWorkbenchAction(new SyncActionDescriptor(MergeAllWindowTabs, MergeAllWindowTabs.ID, MergeAllWindowTabs.LABEL), 'Merge All Windows'); - registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWindowTabsBar, ToggleWindowTabsBar.ID, ToggleWindowTabsBar.LABEL), 'Toggle Window Tabs Bar'); - } + addClasses(this.workbench, 'monaco-workbench', platformClass); + addClasses(document.body, platformClass); // used by our fonts } private initServices(serviceCollection: ServiceCollection): void { @@ -934,17 +907,19 @@ export class Workbench extends Disposable implements IPartService { //#endregion private handleContextKeys(): void { - this.inZenMode = InEditorZenModeContext.bindTo(this.contextKeyService); - IsMacContext.bindTo(this.contextKeyService); IsLinuxContext.bindTo(this.contextKeyService); IsWindowsContext.bindTo(this.contextKeyService); + + const windowConfig = this.configurationService.getValue(); + HasMacNativeTabsContext.bindTo(this.contextKeyService).set(windowConfig && windowConfig.window && windowConfig.window.nativeTabs); + + IsDevelopmentContext.bindTo(this.contextKeyService).set(!this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment); + SupportsWorkspacesContext.bindTo(this.contextKeyService); - const supportsOpenFileFolderContextKey = SupportsOpenFileFolderContext.bindTo(this.contextKeyService); - SupportsWorkspacesContext.bindTo(this.contextKeyService); - if (this.windowService.getConfiguration().remoteAuthority) { - supportsOpenFileFolderContextKey.set(true); - } + SupportsOpenFileFolderContext.bindTo(this.contextKeyService).set(!!this.windowService.getConfiguration().remoteAuthority); + + this.inZenMode = InEditorZenModeContext.bindTo(this.contextKeyService); const sidebarVisibleContextRaw = new RawContextKey('sidebarVisible', false); this.sideBarVisibleContext = sidebarVisibleContextRaw.bindTo(this.contextKeyService); @@ -1372,11 +1347,11 @@ export class Workbench extends Disposable implements IPartService { this.fontAliasing = aliasing; // Remove all - document.body.classList.remove(...fontAliasingValues.map(value => `monaco-font-aliasing-${value}`)); + removeClasses(this.workbench, ...fontAliasingValues.map(value => `monaco-font-aliasing-${value}`)); // Add specific if (fontAliasingValues.some(option => option === aliasing)) { - document.body.classList.add(`monaco-font-aliasing-${aliasing}`); + addClass(this.workbench, `monaco-font-aliasing-${aliasing}`); } } @@ -1996,7 +1971,8 @@ export class Workbench extends Disposable implements IPartService { else if (!hidden && !this.panelPart.getActivePanel()) { const panelToOpen = this.panelPart.getLastActivePanelId(); if (panelToOpen) { - this.panelPart.openPanel(panelToOpen, true); + const focus = !skipLayout; + this.panelPart.openPanel(panelToOpen, focus); } } diff --git a/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts b/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts index e39ddee054b..181fd500468 100644 --- a/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts +++ b/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts @@ -13,7 +13,8 @@ import { URI as Uri } from 'vs/base/common/uri'; import { BackupFileService, BackupFilesModel, hashPath } from 'vs/workbench/services/backup/node/backupFileService'; import { FileService } from 'vs/workbench/services/files/electron-browser/fileService'; import { TextModel, createTextBufferFactory } from 'vs/editor/common/model/textModel'; -import { TestContextService, TestTextResourceConfigurationService, getRandomTestPath, TestLifecycleService, TestEnvironmentService, TestStorageService } from 'vs/workbench/test/workbenchTestServices'; +import { TestContextService, TestTextResourceConfigurationService, TestLifecycleService, TestEnvironmentService, TestStorageService } from 'vs/workbench/test/workbenchTestServices'; +import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; diff --git a/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts b/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts index 51c7a6b149e..6e2ee8b968c 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts @@ -5,8 +5,9 @@ import * as nls from 'vs/nls'; import * as resources from 'vs/base/common/resources'; +import * as objects from 'vs/base/common/objects'; import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService'; -import { IFileService } from 'vs/platform/files/common/files'; +import { IFileService, IFileStat, FileKind } from 'vs/platform/files/common/files'; import { IQuickInputService, IQuickPickItem, IQuickPick } from 'vs/platform/quickinput/common/quickInput'; import { URI } from 'vs/base/common/uri'; import { isWindows } from 'vs/base/common/platform'; @@ -16,6 +17,9 @@ import { IWindowService, IURIToOpen } from 'vs/platform/windows/common/windows'; import { ILabelService } from 'vs/platform/label/common/label'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { getIconClasses } from 'vs/editor/common/services/getIconClasses'; interface FileQuickPickItem extends IQuickPickItem { uri: URI; @@ -28,13 +32,13 @@ const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i export class RemoteFileDialog { private fallbackPickerButton = { iconPath: this.getAlternateDialogIcons(), tooltip: 'Use Alternate File System' }; - private acceptButton = { iconPath: this.getIcons('accept.svg'), tooltip: 'Select' }; - private cancelButton = { iconPath: this.getIcons('cancel.svg'), tooltip: 'Cancel' }; + private currentFolder: URI; private filePickBox: IQuickPick; private allowFileSelection: boolean; private allowFolderSelection: boolean; private remoteAuthority: string | undefined; + private requiresTrailing: boolean; constructor( @IFileService private readonly remoteFileService: RemoteFileService, @@ -44,6 +48,8 @@ export class RemoteFileDialog { @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @INotificationService private readonly notificationService: INotificationService, @IFileDialogService private readonly fileDialogService: IFileDialogService, + @IModelService private readonly modelService: IModelService, + @IModeService private readonly modeService: IModeService, ) { this.remoteAuthority = this.windowService.getConfiguration().remoteAuthority; } @@ -55,8 +61,9 @@ export class RemoteFileDialog { return Promise.resolve(undefined); } - const title = nls.localize('remoteFileDialog.openTitle', 'Open File or Folder'); - return this.pickResource({ title, defaultUri, canSelectFiles: true, canSelectFolders: true, availableFileSystems: options.availableFileSystems }).then(async fileFolderUri => { + const remoteOptions: IOpenDialogOptions = objects.deepClone(options); + remoteOptions.defaultUri = defaultUri; + return this.pickResource(remoteOptions).then(async fileFolderUri => { if (fileFolderUri) { const stat = await this.remoteFileService.resolveFile(fileFolderUri); return [{ uri: fileFolderUri, typeHint: stat.isDirectory ? 'folder' : 'file' }]; @@ -67,47 +74,20 @@ export class RemoteFileDialog { } public showSaveDialog(options: ISaveDialogOptions): Promise { + this.requiresTrailing = true; const defaultUri = options.defaultUri ? options.defaultUri : URI.from({ scheme: REMOTE_HOST_SCHEME, authority: this.remoteAuthority, path: '/' }); if (!this.remoteFileService.canHandleResource(defaultUri)) { this.notificationService.info(nls.localize('remoteFileDialog.notConnectedToRemote', 'File system provider for {0} is not available.', defaultUri.toString())); return Promise.resolve(undefined); } - + const remoteOptions: IOpenDialogOptions = objects.deepClone(options); + remoteOptions.defaultUri = resources.dirname(defaultUri); + remoteOptions.canSelectFolders = true; + remoteOptions.canSelectFiles = true; return new Promise((resolve) => { - let saveNameBox = this.quickInputService.createInputBox(); - saveNameBox.title = options.title; - saveNameBox.placeholder = nls.localize('remoteFileDialog.saveTitle', 'Enter the new name of the file'); - saveNameBox.value = ''; - saveNameBox.totalSteps = 2; - saveNameBox.step = 1; - saveNameBox.onDidChangeValue(v => { - saveNameBox.validationMessage = this.isValidBaseName(v) ? void 0 : nls.localize('remoteFileDialog.error.invalidfilename', 'Not a valid file name'); + this.pickResource(remoteOptions, resources.basename(defaultUri)).then(folderUri => { + resolve(folderUri); }); - saveNameBox.buttons = [this.fallbackPickerButton]; - saveNameBox.onDidTriggerButton(button => { - if (button === this.fallbackPickerButton) { - options.availableFileSystems.shift(); - this.fileDialogService.showSaveDialog(options).then(result => { - resolve(result); - }); - } - saveNameBox.dispose(); - }); - saveNameBox.onDidAccept(_ => { - const name = saveNameBox.value; - if (this.isValidBaseName(name)) { - saveNameBox.hide(); - this.pickResource({ defaultUri: defaultUri, canSelectFolders: true, title: nls.localize('remoteFileDialogerror.titleFolderPage', 'Folder for \'{0}\'', name), availableFileSystems: options.availableFileSystems }, { step: 2, totalSteps: 2 }).then(folderUri => { - if (folderUri) { - resolve(this.remoteUriFrom(this.remotePathJoin(folderUri, name))); - } else { - resolve(undefined); - } - saveNameBox.dispose(); - }); - } - }); - saveNameBox.show(); }); } @@ -115,11 +95,7 @@ export class RemoteFileDialog { return URI.from({ scheme: REMOTE_HOST_SCHEME, authority: this.remoteAuthority, path }); } - private remotePathJoin(firstPart: URI, secondPart: string): string { - return this.labelService.getUriLabel(resources.joinPath(firstPart, secondPart)); - } - - private async pickResource(options: IOpenDialogOptions, multiOpts?: { step: number; totalSteps: number; }): Promise { + private async pickResource(options: IOpenDialogOptions, trailing?: string): Promise { this.allowFolderSelection = !!options.canSelectFolders; this.allowFileSelection = !!options.canSelectFiles; const defaultUri = options.defaultUri; @@ -127,74 +103,58 @@ export class RemoteFileDialog { return new Promise((resolve) => { this.filePickBox = this.quickInputService.createQuickPick(); - if (multiOpts) { - this.filePickBox.totalSteps = multiOpts.totalSteps; - this.filePickBox.step = multiOpts.step; - } + this.filePickBox.matchOnLabel = false; + this.filePickBox.autoFocusOnList = false; let isResolved = false; let isAcceptHandled = false; - this.currentFolder = homedir; - if (options.availableFileSystems.length > 1) { - this.filePickBox.buttons = [this.fallbackPickerButton, this.acceptButton, this.cancelButton]; - } else { - this.filePickBox.buttons = [this.acceptButton, this.cancelButton]; + + if (options.availableFileSystems && options.availableFileSystems.length > 1) { + this.filePickBox.buttons = [this.fallbackPickerButton]; } this.filePickBox.onDidTriggerButton(button => { if (button === this.fallbackPickerButton) { options.availableFileSystems.shift(); isResolved = true; - this.fileDialogService.pickFileAndOpen(options).then(result => { - resolve(result ? result[0] : undefined); - }); - } else if (button === this.acceptButton) { - resolve(this.currentFolder); - isResolved = true; + if (this.requiresTrailing) { + this.fileDialogService.showSaveDialog(options).then(result => { + resolve(result); + }); + } else { + this.fileDialogService.showOpenDialog(options).then(result => { + resolve(result ? result[0] : undefined); + }); + } } this.filePickBox.hide(); }); + this.filePickBox.title = options.title; - this.filePickBox.placeholder = this.labelService.getUriLabel(this.currentFolder, { endWithSeparator: true }); + this.filePickBox.value = this.labelService.getUriLabel(this.currentFolder); this.filePickBox.items = []; this.filePickBox.onDidAccept(_ => { if (isAcceptHandled || this.filePickBox.busy) { return; } + isAcceptHandled = true; - if (this.filePickBox.activeItems.length === 0) { - if (this.allowFolderSelection) { - resolve(this.currentFolder); - isResolved = true; - this.filePickBox.hide(); + this.onDidAccept().then(resolveValue => { + if (resolveValue) { + resolve(resolveValue); } - } else if (this.filePickBox.activeItems.length === 1) { - const item = this.filePickBox.selectedItems[0]; - if (item) { - if (!item.isFolder) { - resolve(item.uri); - isResolved = true; - this.filePickBox.hide(); - } else { - this.updateItems(item.uri); - } - } - } + }); }); this.filePickBox.onDidChangeActive(i => { isAcceptHandled = false; }); - let to: NodeJS.Timer | undefined; this.filePickBox.onDidChangeValue(value => { - if (to) { - clearTimeout(to); - } - if (this.endsWithSlash(value)) { - to = undefined; - this.onValueChange(); - } else { - to = setTimeout(this.onValueChange, 300); + const trimmedPickBoxValue = ((this.filePickBox.value.length > 1) && this.endsWithSlash(this.filePickBox.value)) ? this.filePickBox.value.substr(0, this.filePickBox.value.length - 1) : this.filePickBox.value; + const valueUri = this.remoteUriFrom(trimmedPickBoxValue); + if (!resources.isEqual(this.currentFolder, valueUri)) { + this.tryUpdateItems(value, valueUri); + this.setActiveItems(value); } }); this.filePickBox.onDidHide(() => { @@ -205,27 +165,136 @@ export class RemoteFileDialog { }); this.filePickBox.show(); - this.updateItems(homedir); + this.updateItems(homedir, trailing); }); } - private async onValueChange() { - if (this.filePickBox) { - let fullPath = this.remoteUriFrom(this.filePickBox.value); - let stat = await this.remoteFileService.resolveFile(fullPath); - if (!stat.isDirectory && this.allowFileSelection) { - this.updateItems(resources.dirname(fullPath)); - this.filePickBox.value = resources.basename(fullPath); - } else if (stat.isDirectory) { - this.updateItems(fullPath); + private async onDidAccept(): Promise { + let resolveValue: URI | undefined; + let navigateValue: URI | undefined; + const trimmedPickBoxValue = ((this.filePickBox.value.length > 1) && this.endsWithSlash(this.filePickBox.value)) ? this.filePickBox.value.substr(0, this.filePickBox.value.length - 1) : this.filePickBox.value; + const inputUri = this.remoteUriFrom(trimmedPickBoxValue); + const inputUriDirname = resources.dirname(inputUri); + let stat: IFileStat | undefined; + let statDirname: IFileStat | undefined; + try { + statDirname = await this.remoteFileService.resolveFile(inputUriDirname); + stat = await this.remoteFileService.resolveFile(inputUri); + } catch (e) { + // do nothing + } + + // Find resolve value + if (this.filePickBox.activeItems.length === 0) { + if (!this.requiresTrailing && resources.isEqual(this.currentFolder, inputUri)) { + resolveValue = inputUri; + } else if (this.requiresTrailing && statDirname && statDirname.isDirectory) { + resolveValue = inputUri; + } else if (stat && stat.isDirectory) { + navigateValue = inputUri; + } + } else if (this.filePickBox.activeItems.length === 1) { + const item = this.filePickBox.selectedItems[0]; + if (item) { + if (!item.isFolder) { + resolveValue = item.uri; + } else { + navigateValue = item.uri; + } + } + } + + if (resolveValue) { + if (this.validate(resolveValue)) { + return Promise.resolve(resolveValue); + } + } else if (navigateValue) { + // Try to navigate into the folder + this.updateItems(navigateValue); + } else { + // validation error. Path does not exist. + } + return Promise.resolve(undefined); + } + + private async tryUpdateItems(value: string, valueUri: URI) { + if (this.endsWithSlash(value) || (!resources.isEqual(this.currentFolder, resources.dirname(valueUri)) && resources.isEqualOrParent(this.currentFolder, resources.dirname(valueUri)))) { + let stat: IFileStat | undefined; + try { + stat = await this.remoteFileService.resolveFile(valueUri); + } catch (e) { + // do nothing + } + if (stat && stat.isDirectory && (resources.basename(valueUri) !== '.')) { + this.updateItems(valueUri); + } else { + const inputUriDirname = resources.dirname(valueUri); + if (!resources.isEqual(this.currentFolder, inputUriDirname)) { + const statWithoutTrailing = await this.remoteFileService.resolveFile(inputUriDirname); + if (statWithoutTrailing && statWithoutTrailing.isDirectory && (resources.basename(valueUri) !== '.')) { + this.updateItems(inputUriDirname, resources.basename(valueUri)); + } + } } } } - private updateItems(newFolder: URI) { + private setActiveItems(value: string) { + const inputBasename = resources.basename(this.remoteUriFrom(value)); + let hasMatch = false; + for (let i = 0; i < this.filePickBox.items.length; i++) { + const item = this.filePickBox.items[i]; + const itemBasename = resources.basename(item.uri); + if ((itemBasename.length >= inputBasename.length) && (itemBasename.substr(0, inputBasename.length) === inputBasename)) { + this.filePickBox.activeItems = [item]; + hasMatch = true; + break; + } + } + if (!hasMatch) { + this.filePickBox.activeItems = []; + } + } + + private async validate(uri: URI): Promise { + let stat: IFileStat | undefined; + let statDirname: IFileStat | undefined; + try { + stat = await this.remoteFileService.resolveFile(uri); + statDirname = await this.remoteFileService.resolveFile(resources.dirname(uri)); + } catch (e) { + // do nothing + } + + if (this.requiresTrailing) { // save + if (statDirname.isDirectory) { + // Can't do this + return Promise.resolve(false); + } else if (stat) { + // This is replacing a file. Not supported yet. + return Promise.resolve(false); + } else if (!this.isValidBaseName(resources.basename(uri))) { + // Filename not allowed + return Promise.resolve(false); + } + } else { // open + if (!stat) { + // File or folder doesn't exist + return Promise.resolve(false); + } else if (stat.isDirectory && !this.allowFolderSelection) { + // Folder selected when folder selection not permitted + return Promise.resolve(false); + } else if (!stat.isDirectory && !this.allowFileSelection) { + // File selected when file selection not permitted + return Promise.resolve(false); + } + } + return Promise.resolve(true); + } + + private updateItems(newFolder: URI, trailing?: string) { this.currentFolder = newFolder; - this.filePickBox.placeholder = this.labelService.getUriLabel(newFolder, { endWithSeparator: true }); - this.filePickBox.value = ''; + this.filePickBox.value = trailing ? this.labelService.getUriLabel(resources.joinPath(newFolder, trailing)) : this.labelService.getUriLabel(newFolder, { endWithSeparator: true }); this.filePickBox.busy = true; this.createItems(this.currentFolder).then(items => { this.filePickBox.items = items; @@ -316,9 +385,9 @@ export class RemoteFileDialog { const stat = await this.remoteFileService.resolveFile(fullPath); if (stat.isDirectory) { filename = this.basenameWithTrailingSlash(fullPath); - return { label: filename, uri: fullPath, isFolder: true }; + return { label: filename, uri: fullPath, isFolder: true, iconClasses: getIconClasses(this.modelService, this.modeService, fullPath || undefined, FileKind.FOLDER) }; } else if (!stat.isDirectory && this.allowFileSelection) { - return { label: filename, uri: fullPath, isFolder: false }; + return { label: filename, uri: fullPath, isFolder: false, iconClasses: getIconClasses(this.modelService, this.modeService, fullPath || undefined) }; } return null; } catch (e) { @@ -326,17 +395,10 @@ export class RemoteFileDialog { } } - private getIcons(name: string): { light: URI, dark: URI } { - return { - light: URI.parse(require.toUrl(`vs/workbench/services/dialogs/media/light/${name}`)), - dark: URI.parse(require.toUrl(`vs/workbench/services/dialogs/media/dark/${name}`)) - }; - } - private getAlternateDialogIcons(): { light: URI, dark: URI } { return { - dark: URI.parse(require.toUrl(`vs/editor/contrib/suggest/media/Folder_inverse_16x.svg`)), - light: URI.parse(require.toUrl(`vs/editor/contrib/suggest/media/Folder_16x.svg`)) + dark: URI.parse(require.toUrl(`vs/workbench/services/dialogs/media/dark/Folder.svg`)), + light: URI.parse(require.toUrl(`vs/workbench/services/dialogs/media/light/Folder_inverse.svg`)) }; } } \ No newline at end of file diff --git a/src/vs/workbench/services/dialogs/media/dark/Folder.svg b/src/vs/workbench/services/dialogs/media/dark/Folder.svg new file mode 100644 index 00000000000..3d64ae71db4 --- /dev/null +++ b/src/vs/workbench/services/dialogs/media/dark/Folder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/services/dialogs/media/dark/accept.svg b/src/vs/workbench/services/dialogs/media/dark/accept.svg deleted file mode 100644 index c225b2f597f..00000000000 --- a/src/vs/workbench/services/dialogs/media/dark/accept.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/services/dialogs/media/dark/cancel.svg b/src/vs/workbench/services/dialogs/media/dark/cancel.svg deleted file mode 100644 index 751e89b3b02..00000000000 --- a/src/vs/workbench/services/dialogs/media/dark/cancel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/services/dialogs/media/light/Folder_inverse.svg b/src/vs/workbench/services/dialogs/media/light/Folder_inverse.svg new file mode 100644 index 00000000000..13b18d18016 --- /dev/null +++ b/src/vs/workbench/services/dialogs/media/light/Folder_inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/services/dialogs/media/light/accept.svg b/src/vs/workbench/services/dialogs/media/light/accept.svg deleted file mode 100644 index d45df06edf8..00000000000 --- a/src/vs/workbench/services/dialogs/media/light/accept.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/services/dialogs/media/light/cancel.svg b/src/vs/workbench/services/dialogs/media/light/cancel.svg deleted file mode 100644 index fde34404d4e..00000000000 --- a/src/vs/workbench/services/dialogs/media/light/cancel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index 7564844b33a..882c487b795 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -70,6 +70,10 @@ export interface EditorGroupLayout { groups: GroupLayoutArgument[]; } +export interface ICloseEditorOptions { + preserveFocus?: boolean; +} + export interface IMoveEditorOptions { index?: number; inactive?: boolean; @@ -430,7 +434,7 @@ export interface IEditorGroup { * * @returns a promise when the editor is closed. */ - closeEditor(editor?: IEditorInput): Promise; + closeEditor(editor?: IEditorInput, options?: ICloseEditorOptions): Promise; /** * Closes specific editors in this group. This may trigger a confirmation dialog if @@ -438,7 +442,7 @@ export interface IEditorGroup { * * @returns a promise when all editors are closed. */ - closeEditors(editors: IEditorInput[] | ICloseEditorsFilter): Promise; + closeEditors(editors: IEditorInput[] | ICloseEditorsFilter, options?: ICloseEditorOptions): Promise; /** * Closes all editors from the group. This may trigger a confirmation dialog if 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 e794eef02c5..88e89e9c270 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -193,13 +193,13 @@ suite('Editor service', () => { const fileInput1Again = service.createInput({ resource: fileResource1 }); assert.equal(fileInput1Again, fileInput1); - fileInput1Again.dispose(); + fileInput1Again!.dispose(); - assert.ok(fileInput1.isDisposed()); + assert.ok(fileInput1!.isDisposed()); const fileInput1AgainAndAgain = service.createInput({ resource: fileResource1 }); assert.notEqual(fileInput1AgainAndAgain, fileInput1); - assert.ok(!fileInput1AgainAndAgain.isDisposed()); + assert.ok(!fileInput1AgainAndAgain!.isDisposed()); // Cached Input (Resource) const resource1 = URI.from({ scheme: 'custom', path: '/foo/bar/cache1.js' }); @@ -215,13 +215,13 @@ suite('Editor service', () => { const input1Again = service.createInput({ resource: resource1 }); assert.equal(input1Again, input1); - input1Again.dispose(); + input1Again!.dispose(); - assert.ok(input1.isDisposed()); + assert.ok(input1!.isDisposed()); const input1AgainAndAgain = service.createInput({ resource: resource1 }); assert.notEqual(input1AgainAndAgain, input1); - assert.ok(!input1AgainAndAgain.isDisposed()); + assert.ok(!input1AgainAndAgain!.isDisposed()); }); test('createInput', function () { @@ -260,7 +260,7 @@ suite('Editor service', () => { class MyEditor extends BaseEditor { constructor(id: string) { - super(id, undefined, new TestThemeService(), new TestStorageService()); + super(id, undefined!, new TestThemeService(), new TestStorageService()); } getId(): string { diff --git a/src/vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler.ts b/src/vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler.ts index f8afb7bc4f5..80700c6aa9a 100644 --- a/src/vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler.ts @@ -90,9 +90,15 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { } if (!confirmed) { + let uriString = uri.toString(); + + if (uriString.length > 40) { + uriString = `${uriString.substring(0, 30)}...${uriString.substring(uriString.length - 5)}`; + } + const result = await this.dialogService.confirm({ message: localize('confirmUrl', "Allow an extension to open this URL?", extensionId), - detail: `${extension.displayName || extension.name} (${extensionId}) wants to open a URL:\n\n${uri.toString()}`, + detail: `${extension.displayName || extension.name} (${extensionId}) wants to open a URL:\n\n${uriString}`, primaryButton: localize('open', "&&Open"), type: 'question' }); diff --git a/src/vs/workbench/services/extensions/node/extensionHostMain.ts b/src/vs/workbench/services/extensions/node/extensionHostMain.ts index 6f62be729ad..66e03162e40 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostMain.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostMain.ts @@ -73,7 +73,7 @@ export class ExtensionHostMain { this.disposables.push(this._extHostLogService); this._searchRequestIdProvider = new Counter(); - const extHostWorkspace = new ExtHostWorkspace(rpcProtocol, this._extHostLogService, this._searchRequestIdProvider); + const extHostWorkspace = new ExtHostWorkspace(rpcProtocol, this._extHostLogService, this._searchRequestIdProvider, initData.workspace); this._extHostLogService.info('extension host started'); this._extHostLogService.trace('initData', initData); diff --git a/src/vs/workbench/services/extensions/node/proxyResolver.ts b/src/vs/workbench/services/extensions/node/proxyResolver.ts index dba03553536..98fed1fac42 100644 --- a/src/vs/workbench/services/extensions/node/proxyResolver.ts +++ b/src/vs/workbench/services/extensions/node/proxyResolver.ts @@ -8,7 +8,7 @@ import * as https from 'https'; import * as nodeurl from 'url'; import { assign } from 'vs/base/common/objects'; -import { ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; +import { IExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostConfigProvider } from 'vs/workbench/api/node/extHostConfiguration'; import { ProxyAgent } from 'vscode-proxy-agent'; import { MainThreadTelemetryShape } from 'vs/workbench/api/node/extHost.protocol'; @@ -25,7 +25,7 @@ interface ConnectionResult { } export function connectProxyResolver( - extHostWorkspace: ExtHostWorkspaceProvider, + extHostWorkspace: IExtHostWorkspaceProvider, configProvider: ExtHostConfigProvider, extensionService: ExtHostExtensionService, extHostLogService: ExtHostLogService, @@ -39,7 +39,7 @@ export function connectProxyResolver( const maxCacheEntries = 5000; // Cache can grow twice that much due to 'oldCache'. function setupProxyResolution( - extHostWorkspace: ExtHostWorkspaceProvider, + extHostWorkspace: IExtHostWorkspaceProvider, configProvider: ExtHostConfigProvider, extHostLogService: ExtHostLogService, mainThreadTelemetry: MainThreadTelemetryShape @@ -185,7 +185,7 @@ function collectResult(results: ConnectionResult[], resolveProxy: string, connec }); } -function findOrCreateResult(results: ConnectionResult[], proxy: string, connection: string, code: string): ConnectionResult | undefined { +function findOrCreateResult(results: ConnectionResult[], proxy: string, connection: string, code: string): ConnectionResult { for (const result of results) { if (result.proxy === proxy && result.connection === connection && result.code === code) { return result; @@ -196,7 +196,7 @@ function findOrCreateResult(results: ConnectionResult[], proxy: string, connecti return result; } -function proxyFromConfigURL(configURL: string) { +function proxyFromConfigURL(configURL: string | undefined) { const url = (configURL || '').trim(); const i = url.indexOf('://'); if (i === -1) { diff --git a/src/vs/workbench/services/files/test/electron-browser/fileService.test.ts b/src/vs/workbench/services/files/test/electron-browser/fileService.test.ts index c36d6a01d34..279e1e47c5d 100644 --- a/src/vs/workbench/services/files/test/electron-browser/fileService.test.ts +++ b/src/vs/workbench/services/files/test/electron-browser/fileService.test.ts @@ -14,7 +14,8 @@ import * as uuid from 'vs/base/common/uuid'; import * as pfs from 'vs/base/node/pfs'; import * as encodingLib from 'vs/base/node/encoding'; import * as utils from 'vs/workbench/services/files/test/electron-browser/utils'; -import { TestEnvironmentService, TestContextService, TestTextResourceConfigurationService, getRandomTestPath, TestLifecycleService, TestStorageService } from 'vs/workbench/test/workbenchTestServices'; +import { TestEnvironmentService, TestContextService, TestTextResourceConfigurationService, TestLifecycleService, TestStorageService } from 'vs/workbench/test/workbenchTestServices'; +import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; diff --git a/src/vs/workbench/services/remote/node/remoteAgentEnvironmentChannel.ts b/src/vs/workbench/services/remote/node/remoteAgentEnvironmentChannel.ts index 8ed6173c312..224b27d9a75 100644 --- a/src/vs/workbench/services/remote/node/remoteAgentEnvironmentChannel.ts +++ b/src/vs/workbench/services/remote/node/remoteAgentEnvironmentChannel.ts @@ -3,12 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { OperatingSystem } from 'vs/base/common/platform'; +import * as platform from 'vs/base/common/platform'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IChannel } from 'vs/base/parts/ipc/node/ipc'; import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { IRemoteAgentEnvironment } from 'vs/workbench/services/remote/node/remoteAgentService'; +export interface IGetEnvironmentDataArguments { + language: string; + remoteAuthority: string; + extensionDevelopmentPath: UriComponents | undefined; +} + export interface IRemoteAgentEnvironmentDTO { pid: number; appRoot: UriComponents; @@ -18,7 +24,7 @@ export interface IRemoteAgentEnvironmentDTO { extensionHostLogsPath: UriComponents; globalStorageHome: UriComponents; extensions: IExtensionDescription[]; - os: OperatingSystem; + os: platform.OperatingSystem; syncExtensions: boolean; } @@ -27,7 +33,12 @@ export class RemoteExtensionEnvironmentChannelClient { constructor(private channel: IChannel) { } getEnvironmentData(remoteAuthority: string, extensionDevelopmentPath?: URI): Promise { - return this.channel.call('getEnvironmentData', [remoteAuthority, extensionDevelopmentPath]) + const args: IGetEnvironmentDataArguments = { + language: platform.language, + remoteAuthority, + extensionDevelopmentPath + }; + return this.channel.call('getEnvironmentData', args) .then((data: IRemoteAgentEnvironmentDTO): IRemoteAgentEnvironment => { return { pid: data.pid, diff --git a/src/vs/workbench/services/themes/browser/colorThemeData.ts b/src/vs/workbench/services/themes/browser/colorThemeData.ts index 0f0f33b306d..0ed81859963 100644 --- a/src/vs/workbench/services/themes/browser/colorThemeData.ts +++ b/src/vs/workbench/services/themes/browser/colorThemeData.ts @@ -36,17 +36,26 @@ const tokenGroupToScopesMap: { [setting: string]: string[] } = { export class ColorThemeData implements IColorTheme { - private constructor() { - } - id: string; label: string; settingsId: string; description?: string; isLoaded: boolean; location?: URI; - watch: boolean; - extensionData: ExtensionData; + watch?: boolean; + extensionData?: ExtensionData; + + private themeTokenColors: ITokenColorizationRule[] = []; + private customTokenColors: ITokenColorizationRule[] = []; + private colorMap: IColorMap = {}; + private customColorMap: IColorMap = {}; + + private constructor(id: string, label: string, settingsId: string) { + this.id = id; + this.label = label; + this.settingsId = settingsId; + this.isLoaded = false; + } get tokenColors(): ITokenColorizationRule[] { // Add the custom colors after the theme colors @@ -54,10 +63,7 @@ export class ColorThemeData implements IColorTheme { return this.themeTokenColors.concat(this.customTokenColors); } - private themeTokenColors: ITokenColorizationRule[] = []; - private customTokenColors: ITokenColorizationRule[] = []; - private colorMap: IColorMap = {}; - private customColorMap: IColorMap = {}; + public getColor(colorId: ColorIdentifier, useDefault?: boolean): Color | undefined { let color: Color | undefined = this.customColorMap[colorId]; @@ -212,10 +218,7 @@ export class ColorThemeData implements IColorTheme { // constructors static createUnloadedTheme(id: string): ColorThemeData { - let themeData = new ColorThemeData(); - themeData.id = id; - themeData.label = ''; - themeData.settingsId = '__' + id; + let themeData = new ColorThemeData(id, '', '__' + id); themeData.isLoaded = false; themeData.themeTokenColors = [{ settings: {} }]; themeData.watch = false; @@ -223,10 +226,7 @@ export class ColorThemeData implements IColorTheme { } static createLoadedEmptyTheme(id: string, settingsId: string): ColorThemeData { - let themeData = new ColorThemeData(); - themeData.id = id; - themeData.label = ''; - themeData.settingsId = settingsId; + let themeData = new ColorThemeData(id, '', settingsId); themeData.isLoaded = true; themeData.themeTokenColors = [{ settings: {} }]; themeData.watch = false; @@ -236,7 +236,7 @@ export class ColorThemeData implements IColorTheme { static fromStorageData(input: string): ColorThemeData | undefined { try { let data = JSON.parse(input); - let theme = new ColorThemeData(); + let theme = new ColorThemeData('', '', ''); for (let key in data) { switch (key) { case 'colorMap': @@ -251,6 +251,9 @@ export class ColorThemeData implements IColorTheme { break; } } + if (!theme.id || !theme.settingsId) { + return undefined; + } return theme; } catch (e) { return undefined; @@ -258,12 +261,12 @@ export class ColorThemeData implements IColorTheme { } static fromExtensionTheme(theme: IThemeExtensionPoint, colorThemeLocation: URI, extensionData: ExtensionData): ColorThemeData { - let baseTheme: string = theme['uiTheme'] || 'vs-dark'; - let themeSelector = toCSSSelector(extensionData.extensionId, theme.path); - let themeData = new ColorThemeData(); - themeData.id = `${baseTheme} ${themeSelector}`; - themeData.label = theme.label || basename(theme.path); - themeData.settingsId = theme.id || themeData.label; + const baseTheme: string = theme['uiTheme'] || 'vs-dark'; + const themeSelector = toCSSSelector(extensionData.extensionId, theme.path); + const id = `${baseTheme} ${themeSelector}`; + const label = theme.label || basename(theme.path); + const settingsId = theme.id || label; + const themeData = new ColorThemeData(id, label, settingsId); themeData.description = theme.description; themeData.watch = theme._watch === true; themeData.location = colorThemeLocation; diff --git a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts index 6540a94ea80..aefaac93551 100644 --- a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts @@ -420,7 +420,9 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { this.onColorThemeChange.fire(this.currentColorTheme); // remember theme data for a quick restore - this.storageService.store(PERSISTED_THEME_STORAGE_KEY, newTheme.toStorageData(), StorageScope.GLOBAL); + if (newTheme.isLoaded) { + this.storageService.store(PERSISTED_THEME_STORAGE_KEY, newTheme.toStorageData(), StorageScope.GLOBAL); + } return this.writeColorThemeConfiguration(settingsTarget); } @@ -479,7 +481,9 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { this.doSetFileIconTheme(newIconTheme); // remember theme data for a quick restore - this.storageService.store(PERSISTED_ICON_THEME_STORAGE_KEY, newIconTheme.toStorageData(), StorageScope.GLOBAL); + if (newIconTheme.isLoaded) { + this.storageService.store(PERSISTED_ICON_THEME_STORAGE_KEY, newIconTheme.toStorageData(), StorageScope.GLOBAL); + } return this.writeFileIconConfiguration(settingsTarget); }; diff --git a/src/vs/workbench/services/themes/common/fileIconThemeData.ts b/src/vs/workbench/services/themes/common/fileIconThemeData.ts index 8b345ada938..0ee73d56bb9 100644 --- a/src/vs/workbench/services/themes/common/fileIconThemeData.ts +++ b/src/vs/workbench/services/themes/common/fileIconThemeData.ts @@ -23,11 +23,19 @@ export class FileIconThemeData implements IFileIconTheme { isLoaded: boolean; location?: URI; extensionData?: ExtensionData; - watch: boolean; + watch?: boolean; styleSheetContent?: string; - private constructor() { } + private constructor(id: string, label: string, settingsId: string | null) { + this.id = id; + this.label = label; + this.settingsId = settingsId; + this.isLoaded = false; + this.hasFileIcons = false; + this.hasFolderIcons = false; + this.hidesExplorerArrows = false; + } public ensureLoaded(fileService: IFileService): Promise { return !this.isLoaded ? this.load(fileService) : Promise.resolve(this.styleSheetContent); @@ -53,10 +61,12 @@ export class FileIconThemeData implements IFileIconTheme { } static fromExtensionTheme(iconTheme: IThemeExtensionPoint, iconThemeLocation: URI, extensionData: ExtensionData): FileIconThemeData { - let themeData = new FileIconThemeData(); - themeData.id = extensionData.extensionId + '-' + iconTheme.id; - themeData.label = iconTheme.label || Paths.basename(iconTheme.path); - themeData.settingsId = iconTheme.id; + const id = extensionData.extensionId + '-' + iconTheme.id; + const label = iconTheme.label || Paths.basename(iconTheme.path); + const settingsId = iconTheme.id; + + const themeData = new FileIconThemeData(id, label, settingsId); + themeData.description = iconTheme.description; themeData.location = iconThemeLocation; themeData.extensionData = extensionData; @@ -70,10 +80,7 @@ export class FileIconThemeData implements IFileIconTheme { static noIconTheme(): FileIconThemeData { let themeData = FileIconThemeData._noIconTheme; if (!themeData) { - themeData = FileIconThemeData._noIconTheme = new FileIconThemeData(); - themeData.id = ''; - themeData.label = ''; - themeData.settingsId = null; + themeData = FileIconThemeData._noIconTheme = new FileIconThemeData('', '', null); themeData.hasFileIcons = false; themeData.hasFolderIcons = false; themeData.hidesExplorerArrows = false; @@ -85,10 +92,7 @@ export class FileIconThemeData implements IFileIconTheme { } static createUnloadedTheme(id: string): FileIconThemeData { - let themeData = new FileIconThemeData(); - themeData.id = id; - themeData.label = ''; - themeData.settingsId = '__' + id; + const themeData = new FileIconThemeData(id, '', '__' + id); themeData.isLoaded = false; themeData.hasFileIcons = false; themeData.hasFolderIcons = false; @@ -101,7 +105,7 @@ export class FileIconThemeData implements IFileIconTheme { static fromStorageData(input: string): FileIconThemeData | null { try { let data = JSON.parse(input); - let theme = new FileIconThemeData(); + const theme = new FileIconThemeData('', '', null); for (let key in data) { switch (key) { case 'id': diff --git a/src/vs/workbench/services/themes/common/workbenchThemeService.ts b/src/vs/workbench/services/themes/common/workbenchThemeService.ts index 533d44586f5..1e4da9260cc 100644 --- a/src/vs/workbench/services/themes/common/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/common/workbenchThemeService.ts @@ -27,7 +27,7 @@ export interface IColorTheme extends ITheme { readonly id: string; readonly label: string; readonly settingsId: string; - readonly extensionData: ExtensionData; + readonly extensionData?: ExtensionData; readonly description?: string; readonly isLoaded: boolean; readonly tokenColors: ITokenColorizationRule[]; diff --git a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts index e8d1abc034c..ac0062c6c24 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; -import { ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostConfigProvider } from 'vs/workbench/api/node/extHostConfiguration'; import { MainThreadConfigurationShape, IConfigurationInitData } from 'vs/workbench/api/node/extHost.protocol'; import { ConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; @@ -31,7 +31,7 @@ suite('ExtHostConfiguration', function () { if (!shape) { shape = new class extends mock() { }; } - return new ExtHostConfigProvider(shape, new ExtHostWorkspaceProvider(new TestRPCProtocol(), null, new NullLogService(), new Counter()), createConfigurationData(contents)); + return new ExtHostConfigProvider(shape, new ExtHostWorkspace(new TestRPCProtocol(), new NullLogService(), new Counter()), createConfigurationData(contents)); } function createConfigurationData(contents: any): IConfigurationInitData { @@ -265,7 +265,7 @@ suite('ExtHostConfiguration', function () { test('inspect in no workspace context', function () { const testObject = new ExtHostConfigProvider( new class extends mock() { }, - new ExtHostWorkspaceProvider(new TestRPCProtocol(), null, new NullLogService(), new Counter()), + new ExtHostWorkspace(new TestRPCProtocol(), new NullLogService(), new Counter()), { defaults: new ConfigurationModel({ 'editor': { @@ -306,13 +306,15 @@ suite('ExtHostConfiguration', function () { } }, ['editor.wordWrap']); folders[workspaceUri.toString()] = workspace; + const extHostWorkspace = new ExtHostWorkspace(new TestRPCProtocol(), new NullLogService(), new Counter()); + extHostWorkspace.$initializeWorkspace({ + 'id': 'foo', + 'folders': [aWorkspaceFolder(URI.file('foo'), 0)], + 'name': 'foo' + }); const testObject = new ExtHostConfigProvider( new class extends mock() { }, - new ExtHostWorkspaceProvider(new TestRPCProtocol(), { - 'id': 'foo', - 'folders': [aWorkspaceFolder(URI.file('foo'), 0)], - 'name': 'foo' - }, new NullLogService(), new Counter()), + extHostWorkspace, { defaults: new ConfigurationModel({ 'editor': { @@ -380,13 +382,15 @@ suite('ExtHostConfiguration', function () { }, ['editor.wordWrap']); folders[thirdRoot.toString()] = new ConfigurationModel({}, []); + const extHostWorkspace = new ExtHostWorkspace(new TestRPCProtocol(), new NullLogService(), new Counter()); + extHostWorkspace.$initializeWorkspace({ + 'id': 'foo', + 'folders': [aWorkspaceFolder(firstRoot, 0), aWorkspaceFolder(secondRoot, 1)], + 'name': 'foo' + }); const testObject = new ExtHostConfigProvider( new class extends mock() { }, - new ExtHostWorkspaceProvider(new TestRPCProtocol(), { - 'id': 'foo', - 'folders': [aWorkspaceFolder(firstRoot, 0), aWorkspaceFolder(secondRoot, 1)], - 'name': 'foo' - }, new NullLogService(), new Counter()), + extHostWorkspace, { defaults: new ConfigurationModel({ 'editor': { @@ -589,13 +593,15 @@ suite('ExtHostConfiguration', function () { test('configuration change event', (done) => { const workspaceFolder = aWorkspaceFolder(URI.file('folder1'), 0); + const extHostWorkspace = new ExtHostWorkspace(new TestRPCProtocol(), new NullLogService(), new Counter()); + extHostWorkspace.$initializeWorkspace({ + 'id': 'foo', + 'folders': [workspaceFolder], + 'name': 'foo' + }); const testObject = new ExtHostConfigProvider( new class extends mock() { }, - new ExtHostWorkspaceProvider(new TestRPCProtocol(), { - 'id': 'foo', - 'folders': [workspaceFolder], - 'name': 'foo' - }, new NullLogService(), new Counter()), + extHostWorkspace, createConfigurationData({ 'farboo': { 'config': false, diff --git a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts index 8cc4279dfd9..40de7dbe2b3 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts @@ -6,15 +6,21 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; import { basename } from 'vs/base/common/path'; -import { ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { TestRPCProtocol } from './testRPCProtocol'; import { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace'; import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; -import { NullLogService } from 'vs/platform/log/common/log'; -import { IMainContext } from 'vs/workbench/api/node/extHost.protocol'; +import { NullLogService, ILogService } from 'vs/platform/log/common/log'; +import { IMainContext, IWorkspaceData } from 'vs/workbench/api/node/extHost.protocol'; import { Counter } from 'vs/base/common/numbers'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +function createExtHostWorkspace(mainContext: IMainContext, data: IWorkspaceData, logService: ILogService, requestIdProvider: Counter): ExtHostWorkspace { + const result = new ExtHostWorkspace(mainContext, logService, requestIdProvider); + result.$initializeWorkspace(data); + return result; +} + suite('ExtHostWorkspace', function () { const extensionDescriptor: IExtensionDescription = { @@ -29,14 +35,14 @@ suite('ExtHostWorkspace', function () { version: undefined! }; - function assertAsRelativePath(workspace: ExtHostWorkspaceProvider, input: string, expected: string, includeWorkspace?: boolean) { + function assertAsRelativePath(workspace: ExtHostWorkspace, input: string, expected: string, includeWorkspace?: boolean) { const actual = workspace.getRelativePath(input, includeWorkspace); assert.equal(actual, expected); } test('asRelativePath', () => { - const ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/Applications/NewsWoWBot'), 0)], name: 'Test' }, new NullLogService(), new Counter()); + const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/Applications/NewsWoWBot'), 0)], name: 'Test' }, new NullLogService(), new Counter()); assertAsRelativePath(ws, '/Coding/Applications/NewsWoWBot/bernd/das/brot', 'bernd/das/brot'); assertAsRelativePath(ws, '/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart', @@ -50,7 +56,7 @@ suite('ExtHostWorkspace', function () { test('asRelativePath, same paths, #11402', function () { const root = '/home/aeschli/workspaces/samples/docker'; const input = '/home/aeschli/workspaces/samples/docker'; - const ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter()); + const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter()); assertAsRelativePath(ws, input, input); @@ -59,20 +65,20 @@ suite('ExtHostWorkspace', function () { }); test('asRelativePath, no workspace', function () { - const ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), null!, new NullLogService(), new Counter()); + const ws = createExtHostWorkspace(new TestRPCProtocol(), null!, new NullLogService(), new Counter()); assertAsRelativePath(ws, '', ''); assertAsRelativePath(ws, '/foo/bar', '/foo/bar'); }); test('asRelativePath, multiple folders', function () { - const ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter()); + const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter()); assertAsRelativePath(ws, '/Coding/One/file.txt', 'One/file.txt'); assertAsRelativePath(ws, '/Coding/Two/files/out.txt', 'Two/files/out.txt'); assertAsRelativePath(ws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt'); }); test('slightly inconsistent behaviour of asRelativePath and getWorkspaceFolder, #31553', function () { - const mrws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter()); + const mrws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter()); assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt'); assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt', true); @@ -84,7 +90,7 @@ suite('ExtHostWorkspace', function () { assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', true); assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', false); - const srws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0)], name: 'Test' }, new NullLogService(), new Counter()); + const srws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0)], name: 'Test' }, new NullLogService(), new Counter()); assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt'); assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt', false); assertAsRelativePath(srws, '/Coding/One/file.txt', 'One/file.txt', true); @@ -94,24 +100,24 @@ suite('ExtHostWorkspace', function () { }); test('getPath, legacy', function () { - let ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); + let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); assert.equal(ws.getPath(), undefined); - ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), null!, new NullLogService(), new Counter()); + ws = createExtHostWorkspace(new TestRPCProtocol(), null!, new NullLogService(), new Counter()); assert.equal(ws.getPath(), undefined); - ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), undefined!, new NullLogService(), new Counter()); + ws = createExtHostWorkspace(new TestRPCProtocol(), undefined!, new NullLogService(), new Counter()); assert.equal(ws.getPath(), undefined); - ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }, new NullLogService(), new Counter()); + ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }, new NullLogService(), new Counter()); assert.equal(ws.getPath()!.replace(/\\/g, '/'), '/Folder'); - ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Folder'), 0)] }, new NullLogService(), new Counter()); + ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Folder'), 0)] }, new NullLogService(), new Counter()); assert.equal(ws.getPath()!.replace(/\\/g, '/'), '/Folder'); }); test('WorkspaceFolder has name and index', function () { - const ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter()); + const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter()); const [one, two] = ws.getWorkspaceFolders()!; @@ -122,7 +128,7 @@ suite('ExtHostWorkspace', function () { }); test('getContainingWorkspaceFolder', () => { - const ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { + const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [ @@ -170,7 +176,7 @@ suite('ExtHostWorkspace', function () { }); test('Multiroot change event should have a delta, #29641', function (done) { - let ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); + let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); let finished = false; const finish = (error?: any) => { @@ -233,7 +239,7 @@ suite('ExtHostWorkspace', function () { }); test('Multiroot change keeps existing workspaces live', function () { - let ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService(), new Counter()); + let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService(), new Counter()); let firstFolder = ws.getWorkspaceFolders()![0]; ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar2'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1, 'renamed')] }); @@ -253,7 +259,7 @@ suite('ExtHostWorkspace', function () { }); test('updateWorkspaceFolders - invalid arguments', function () { - let ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); + let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, null!, null!)); assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0)); @@ -262,7 +268,7 @@ suite('ExtHostWorkspace', function () { assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, 0)); assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, -1)); - ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService(), new Counter()); + ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService(), new Counter()); assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 1)); assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2)); @@ -284,7 +290,7 @@ suite('ExtHostWorkspace', function () { assertRegistered: undefined! }; - const ws = new ExtHostWorkspaceProvider(protocol, { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); + const ws = createExtHostWorkspace(protocol, { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); // // Add one folder @@ -517,7 +523,7 @@ suite('ExtHostWorkspace', function () { } }; - let ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); + let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); let sub = ws.onDidChangeWorkspace(e => { try { assert.throws(() => { @@ -536,7 +542,7 @@ suite('ExtHostWorkspace', function () { }); test('`vscode.workspace.getWorkspaceFolder(file)` don\'t return workspace folder when file open from command line. #36221', function () { - let ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { + let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [ aWorkspaceFolderData(URI.file('c:/Users/marek/Desktop/vsc_test/'), 0) ] diff --git a/src/vs/platform/theme/test/electron-browser/colorRegistry.releaseTest.ts b/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts similarity index 100% rename from src/vs/platform/theme/test/electron-browser/colorRegistry.releaseTest.ts rename to src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 33d9287af94..4eed1759dea 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -42,7 +42,6 @@ import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; import { createTextBufferFactory } from 'vs/editor/common/model/textModel'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { generateUuid } from 'vs/base/common/uuid'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IRecentlyOpened } from 'vs/platform/history/common/history'; @@ -61,7 +60,7 @@ import { IExtensionService, NullExtensionService } from 'vs/workbench/services/e import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IDecorationsService, IResourceDecorationChangeEvent, IDecoration, IDecorationData, IDecorationsProvider } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, toDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupsArrangement, GroupDirection, IAddGroupOptions, IMergeGroupOptions, IMoveEditorOptions, ICopyEditorOptions, IEditorReplacement, IGroupChangeEvent, EditorsOrder, IFindGroupScope, EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupsArrangement, GroupDirection, IAddGroupOptions, IMergeGroupOptions, IMoveEditorOptions, ICopyEditorOptions, IEditorReplacement, IGroupChangeEvent, EditorsOrder, IFindGroupScope, EditorGroupLayout, ICloseEditorOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService, IOpenEditorOverrideHandler, IActiveEditor } from 'vs/workbench/services/editor/common/editorService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; @@ -688,11 +687,11 @@ export class TestEditorGroup implements IEditorGroupView { copyEditor(_editor: IEditorInput, _target: IEditorGroup, _options?: ICopyEditorOptions): void { } - closeEditor(_editor?: IEditorInput): Promise { + closeEditor(_editor?: IEditorInput, options?: ICloseEditorOptions): Promise { return Promise.resolve(); } - closeEditors(_editors: IEditorInput[] | { except?: IEditorInput; direction?: CloseDirection; savedOnly?: boolean; }): Promise { + closeEditors(_editors: IEditorInput[] | { except?: IEditorInput; direction?: CloseDirection; savedOnly?: boolean; }, options?: ICloseEditorOptions): Promise { return Promise.resolve(); } @@ -1473,7 +1472,3 @@ export class TestViewletService implements IViewletService { getProgressIndicator(_id: string): IProgressService | null { return null; } } - -export function getRandomTestPath(tmpdir: string, ...segments: string[]): string { - return join(tmpdir, ...segments, generateUuid()); -} diff --git a/yarn.lock b/yarn.lock index 7f320a02b0b..adbf542f9dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9442,10 +9442,10 @@ vscode-uri@^1.0.6: resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d" integrity sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww== -vscode-xterm@3.12.0-beta4: - version "3.12.0-beta4" - resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.12.0-beta4.tgz#b8ed223e00e6b53efea62e7c7dce5bc2ac556df3" - integrity sha512-coUhJoIIjSlIZ33VCxI6EEyEKSqet41753wfSy/Av3UCv1oiwrrCRfvLdRYC+qdabWDtVy5K7aYYDh1k7WsVeA== +vscode-xterm@3.12.0-beta5: + version "3.12.0-beta5" + resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.12.0-beta5.tgz#cc1ab88fd564c2ddc36269f7e2b5c9740243a409" + integrity sha512-/UiL1pPm5MKllLyUlKwD5TAOAO8PObWAKQ0Hg3Z3tkF2zkNnR+fT0u+J/J6yWFtOoZ27Cj6QhFEfoiH6WSoXVQ== vso-node-api@6.1.2-preview: version "6.1.2-preview"