diff --git a/.eslintplugin/code-ensure-no-disposables-leak-in-test.ts b/.eslintplugin/code-ensure-no-disposables-leak-in-test.ts new file mode 100644 index 00000000000..ae3089036a6 --- /dev/null +++ b/.eslintplugin/code-ensure-no-disposables-leak-in-test.ts @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as eslint from 'eslint'; +import { Node } from 'estree'; + +export = new class EnsureNoDisposablesAreLeakedInTestSuite implements eslint.Rule.RuleModule { + + readonly meta: eslint.Rule.RuleMetaData = { + type: 'problem', + messages: { + ensure: 'Suites should include a call to `ensureNoDisposablesAreLeakedInTestSuite()` to ensure no disposables are leaked in tests.' + } + }; + + create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { + const config = <{ exclude: string[] }>context.options[0]; + + const needle = context.getFilename().replace(/\\/g, '/'); + if (config.exclude.some((e) => needle.endsWith(e))) { + return {}; + } + + return { + [`Program > ExpressionStatement > CallExpression[callee.name='suite']`]: (node: Node) => { + const src = context.getSourceCode().getText(node) + if (!src.includes('ensureNoDisposablesAreLeakedInTestSuite(')) { + context.report({ + node, + messageId: 'ensure', + }); + } + }, + }; + } +}; diff --git a/.eslintrc.json b/.eslintrc.json index fd88130a1e8..34be9c82c21 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -136,6 +136,194 @@ ] } }, + { + "files": [ + "src/vs/**/*.test.ts" + ], + "rules": { + "local/code-ensure-no-disposables-leak-in-test": [ + "warn", + { + // Files should (only) be removed from the list they adopt the leak detector + "exclude": [ + "src/vs/base/parts/sandbox/test/electron-sandbox/globals.test.ts", + "src/vs/base/test/browser/browser.test.ts", + "src/vs/base/test/browser/comparers.test.ts", + "src/vs/base/test/browser/hash.test.ts", + "src/vs/base/test/browser/indexedDB.test.ts", + "src/vs/base/test/browser/ui/menu/menubar.test.ts", + "src/vs/base/test/browser/ui/scrollbar/scrollableElement.test.ts", + "src/vs/base/test/browser/ui/scrollbar/scrollbarState.test.ts", + "src/vs/base/test/common/arrays.test.ts", + "src/vs/base/test/common/arraysFind.test.ts", + "src/vs/base/test/common/cache.test.ts", + "src/vs/base/test/common/charCode.test.ts", + "src/vs/base/test/common/collections.test.ts", + "src/vs/base/test/common/color.test.ts", + "src/vs/base/test/common/console.test.ts", + "src/vs/base/test/common/decorators.test.ts", + "src/vs/base/test/common/diff/diff.test.ts", + "src/vs/base/test/common/errors.test.ts", + "src/vs/base/test/common/filters.perf.test.ts", + "src/vs/base/test/common/filters.test.ts", + "src/vs/base/test/common/iconLabels.test.ts", + "src/vs/base/test/common/iterator.test.ts", + "src/vs/base/test/common/json.test.ts", + "src/vs/base/test/common/jsonEdit.test.ts", + "src/vs/base/test/common/jsonFormatter.test.ts", + "src/vs/base/test/common/keybindings.test.ts", + "src/vs/base/test/common/keyCodes.test.ts", + "src/vs/base/test/common/linkedList.test.ts", + "src/vs/base/test/common/linkedText.test.ts", + "src/vs/base/test/common/map.test.ts", + "src/vs/base/test/common/markdownString.test.ts", + "src/vs/base/test/common/marshalling.test.ts", + "src/vs/base/test/common/naturalLanguage/korean.test.ts", + "src/vs/base/test/common/network.test.ts", + "src/vs/base/test/common/normalization.test.ts", + "src/vs/base/test/common/observable.test.ts", + "src/vs/base/test/common/path.test.ts", + "src/vs/base/test/common/prefixTree.test.ts", + "src/vs/base/test/common/resources.test.ts", + "src/vs/base/test/common/resourceTree.test.ts", + "src/vs/base/test/common/scrollable.test.ts", + "src/vs/base/test/common/skipList.test.ts", + "src/vs/base/test/common/stripComments.test.ts", + "src/vs/base/test/common/ternarySearchtree.test.ts", + "src/vs/base/test/common/types.test.ts", + "src/vs/base/test/common/uri.test.ts", + "src/vs/base/test/common/uuid.test.ts", + "src/vs/base/test/node/crypto.test.ts", + "src/vs/base/test/node/css.build.test.ts", + "src/vs/base/test/node/id.test.ts", + "src/vs/base/test/node/nodeStreams.test.ts", + "src/vs/base/test/node/snapshot.test.ts", + "src/vs/code/test/electron-sandbox/issue/testReporterModel.test.ts", + "src/vs/editor/contrib/codeAction/test/browser/codeActionKeybindingResolver.test.ts", + "src/vs/editor/contrib/codeAction/test/browser/codeActionModel.test.ts", + "src/vs/editor/contrib/dropOrPasteInto/test/browser/editSort.test.ts", + "src/vs/editor/contrib/folding/test/browser/foldingModel.test.ts", + "src/vs/editor/contrib/folding/test/browser/foldingRanges.test.ts", + "src/vs/editor/contrib/folding/test/browser/indentFold.test.ts", + "src/vs/editor/contrib/folding/test/browser/indentRangeProvider.test.ts", + "src/vs/editor/contrib/gotoSymbol/test/browser/referencesModel.test.ts", + "src/vs/editor/contrib/smartSelect/test/browser/smartSelect.test.ts", + "src/vs/editor/contrib/snippet/test/browser/snippetParser.test.ts", + "src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts", + "src/vs/editor/contrib/snippet/test/browser/snippetVariables.test.ts", + "src/vs/editor/contrib/suggest/test/browser/completionModel.test.ts", + "src/vs/editor/contrib/suggest/test/browser/suggestMemory.test.ts", + "src/vs/editor/test/common/services/languageService.test.ts", + "src/vs/editor/test/node/classification/typescript.test.ts", + "src/vs/editor/test/node/diffing/defaultLinesDiffComputer.test.ts", + "src/vs/editor/test/node/diffing/fixtures.test.ts", + "src/vs/platform/configuration/test/common/configuration.test.ts", + "src/vs/platform/configuration/test/common/configurationModels.test.ts", + "src/vs/platform/configuration/test/common/configurationRegistry.test.ts", + "src/vs/platform/contextkey/test/common/contextkey.test.ts", + "src/vs/platform/contextkey/test/common/parser.test.ts", + "src/vs/platform/contextkey/test/common/scanner.test.ts", + "src/vs/platform/extensionManagement/test/common/extensionManagement.test.ts", + "src/vs/platform/extensions/test/common/extensionValidator.test.ts", + "src/vs/platform/externalTerminal/electron-main/externalTerminalService.test.ts", + "src/vs/platform/instantiation/test/common/graph.test.ts", + "src/vs/platform/instantiation/test/common/instantiationService.test.ts", + "src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts", + "src/vs/platform/keybinding/test/common/keybindingLabels.test.ts", + "src/vs/platform/keybinding/test/common/keybindingResolver.test.ts", + "src/vs/platform/markers/test/common/markerService.test.ts", + "src/vs/platform/opener/test/common/opener.test.ts", + "src/vs/platform/progress/test/common/progress.test.ts", + "src/vs/platform/registry/test/common/platform.test.ts", + "src/vs/platform/remote/test/common/remoteHosts.test.ts", + "src/vs/platform/telemetry/test/browser/1dsAppender.test.ts", + "src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts", + "src/vs/platform/userDataSync/test/common/extensionsMerge.test.ts", + "src/vs/platform/userDataSync/test/common/globalStateMerge.test.ts", + "src/vs/platform/userDataSync/test/common/settingsMerge.test.ts", + "src/vs/platform/userDataSync/test/common/snippetsMerge.test.ts", + "src/vs/platform/userDataSync/test/common/userDataProfilesManifestMerge.test.ts", + "src/vs/platform/workspace/test/common/workspace.test.ts", + "src/vs/platform/workspaces/test/electron-main/workspaces.test.ts", + "src/vs/server/test/node/serverConnectionToken.test.ts", + "src/vs/workbench/api/test/browser/extHostApiCommands.test.ts", + "src/vs/workbench/api/test/browser/extHostBulkEdits.test.ts", + "src/vs/workbench/api/test/browser/extHostCommands.test.ts", + "src/vs/workbench/api/test/browser/extHostDocumentSaveParticipant.test.ts", + "src/vs/workbench/api/test/browser/extHostTelemetry.test.ts", + "src/vs/workbench/api/test/browser/extHostTextEditor.test.ts", + "src/vs/workbench/api/test/browser/extHostTypeConverter.test.ts", + "src/vs/workbench/api/test/browser/extHostTypes.test.ts", + "src/vs/workbench/api/test/browser/extHostWorkspace.test.ts", + "src/vs/workbench/api/test/browser/mainThreadConfiguration.test.ts", + "src/vs/workbench/api/test/browser/mainThreadDocuments.test.ts", + "src/vs/workbench/api/test/common/extensionHostMain.test.ts", + "src/vs/workbench/api/test/common/extHostExtensionActivator.test.ts", + "src/vs/workbench/api/test/node/extHostTunnelService.test.ts", + "src/vs/workbench/contrib/bulkEdit/test/browser/bulkCellEdits.test.ts", + "src/vs/workbench/contrib/chat/test/common/chatWordCounter.test.ts", + "src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts", + "src/vs/workbench/contrib/debug/test/browser/breakpoints.test.ts", + "src/vs/workbench/contrib/debug/test/browser/callStack.test.ts", + "src/vs/workbench/contrib/debug/test/browser/debugHover.test.ts", + "src/vs/workbench/contrib/debug/test/browser/repl.test.ts", + "src/vs/workbench/contrib/debug/test/common/debugModel.test.ts", + "src/vs/workbench/contrib/debug/test/node/debugger.test.ts", + "src/vs/workbench/contrib/debug/test/node/streamDebugAdapter.test.ts", + "src/vs/workbench/contrib/debug/test/node/terminals.test.ts", + "src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts", + "src/vs/workbench/contrib/extensions/test/common/extensionQuery.test.ts", + "src/vs/workbench/contrib/extensions/test/electron-sandbox/extension.test.ts", + "src/vs/workbench/contrib/files/test/browser/explorerFileNestingTrie.test.ts", + "src/vs/workbench/contrib/files/test/browser/explorerView.test.ts", + "src/vs/workbench/contrib/notebook/test/browser/cellDnd.test.ts", + "src/vs/workbench/contrib/notebook/test/browser/contrib/contributedStatusBarItemController.test.ts", + "src/vs/workbench/contrib/notebook/test/browser/contrib/executionStatusBarItem.test.ts", + "src/vs/workbench/contrib/notebook/test/browser/contrib/layoutActions.test.ts", + "src/vs/workbench/contrib/notebook/test/browser/contrib/outputCopyTests.test.ts", + "src/vs/workbench/contrib/notebook/test/browser/notebookBrowser.test.ts", + "src/vs/workbench/contrib/notebook/test/browser/notebookExecutionService.test.ts", + "src/vs/workbench/contrib/notebook/test/browser/notebookExecutionStateService.test.ts", + "src/vs/workbench/contrib/notebook/test/browser/notebookTextModel.test.ts", + "src/vs/workbench/contrib/search/test/common/cacheState.test.ts", + "src/vs/workbench/contrib/search/test/common/extractRange.test.ts", + "src/vs/workbench/contrib/snippets/test/browser/snippetFile.test.ts", + "src/vs/workbench/contrib/snippets/test/browser/snippetsRegistry.test.ts", + "src/vs/workbench/contrib/snippets/test/browser/snippetsRewrite.test.ts", + "src/vs/workbench/contrib/tasks/test/common/problemMatcher.test.ts", + "src/vs/workbench/contrib/tasks/test/common/taskConfiguration.test.ts", + "src/vs/workbench/contrib/terminal/test/browser/terminalActions.test.ts", + "src/vs/workbench/contrib/welcomeGettingStarted/test/browser/gettingStartedMarkdownRenderer.test.ts", + "src/vs/workbench/services/commands/test/common/commandService.test.ts", + "src/vs/workbench/services/configuration/test/common/configurationModels.test.ts", + "src/vs/workbench/services/dialogs/test/electron-sandbox/fileDialogService.test.ts", + "src/vs/workbench/services/editor/test/browser/editorResolverService.test.ts", + "src/vs/workbench/services/extensions/test/common/extensionDescriptionRegistry.test.ts", + "src/vs/workbench/services/keybinding/test/browser/keybindingIO.test.ts", + "src/vs/workbench/services/keybinding/test/node/fallbackKeyboardMapper.test.ts", + "src/vs/workbench/services/keybinding/test/node/macLinuxKeyboardMapper.test.ts", + "src/vs/workbench/services/keybinding/test/node/windowsKeyboardMapper.test.ts", + "src/vs/workbench/services/preferences/test/browser/preferencesService.test.ts", + "src/vs/workbench/services/preferences/test/common/preferencesValidation.test.ts", + "src/vs/workbench/services/search/test/browser/queryBuilder.test.ts", + "src/vs/workbench/services/search/test/common/ignoreFile.test.ts", + "src/vs/workbench/services/search/test/common/queryBuilder.test.ts", + "src/vs/workbench/services/search/test/common/replace.test.ts", + "src/vs/workbench/services/search/test/common/search.test.ts", + "src/vs/workbench/services/search/test/common/searchHelpers.test.ts", + "src/vs/workbench/services/search/test/node/ripgrepFileSearch.test.ts", + "src/vs/workbench/services/search/test/node/ripgrepTextSearchEngineUtils.test.ts", + "src/vs/workbench/services/telemetry/test/browser/commonProperties.test.ts", + "src/vs/workbench/services/themes/test/node/tokenStyleResolving.test.ts", + "src/vs/workbench/services/userActivity/test/browser/domActivityTracker.test.ts", + "src/vs/workbench/services/workspaces/test/browser/workspaces.test.ts", + "src/vs/workbench/services/workspaces/test/common/workspaceTrust.test.ts", + "src/vs/workbench/test/browser/quickAccess.test.ts" + ] + } + ] + } + }, { "files": [ "**/vscode.d.ts", diff --git a/.github/classifier.json b/.github/classifier.json index 21b8d51cd6c..992354698ce 100644 --- a/.github/classifier.json +++ b/.github/classifier.json @@ -253,6 +253,7 @@ "tokenization": {"assign": ["alexdima"]}, "touch/pointer": {"assign": []}, "trackpad/scroll": {"assign": []}, + "tree-sticky-scroll": {"assign": ["benibenj"]}, "tree-views": {"assign": ["alexr00"]}, "tree-widget": {"assign": ["joaomoreno"]}, "typehierarchy": {"assign": ["jrieken"]}, @@ -272,6 +273,7 @@ "webview": {"assign": ["mjbvz"]}, "webview-views": {"assign": ["mjbvz"]}, "workbench-actions": {"assign": ["bpasero"]}, + "workbench-auxwindow": {"assign": ["bpasero"]}, "workbench-banner": {"assign": ["lszomoru", "sbatten"]}, "workbench-cli": {"assign": ["bpasero"]}, "workbench-diagnostics": {"assign": ["Tyriar"]}, diff --git a/.vscode/notebooks/grooming.github-issues b/.vscode/notebooks/grooming.github-issues index 2d4ca60063d..ed6b0552fa5 100644 --- a/.vscode/notebooks/grooming.github-issues +++ b/.vscode/notebooks/grooming.github-issues @@ -12,7 +12,7 @@ { "kind": 1, "language": "markdown", - "value": "#### Missing Type label\n" + "value": "#### Missing Type label\r\n" }, { "kind": 2, @@ -22,17 +22,17 @@ { "kind": 1, "language": "markdown", - "value": "#### Missing Area Label\n\nFeature area labels are light or strong blue (`1d76db` or `c5def5`) and they denote a specific feature or feature area, like `editor-clipboard` or `file-explorer`\n" + "value": "#### Missing Area Label\r\n\r\nFeature area labels are light or strong blue (`1d76db` or `c5def5`) and they denote a specific feature or feature area, like `editor-clipboard` or `file-explorer`\r\n" }, { "kind": 2, "language": "github-issues", - "value": "repo:microsoft/vscode assignee:@me is:open type:issue -label:\"info-needed\" -label:api -label:api-finalization -label:api-proposal -label:authentication -label:bisect-ext -label:bracket-pair-colorization -label:bracket-pair-guides -label:breadcrumbs -label:callhierarchy -label:chrome-devtools -label:cloud-changes -label:code-lens -label:command-center -label:comments -label:config -label:containers -label:context-keys -label:continue-working-on -label:css-less-scss -label:custom-editors -label:debug -label:debug-disassembly -label:dialogs -label:diff-editor -label:dropdown -label:editor-api -label:editor-autoclosing -label:editor-autoindent -label:editor-bracket-matching -label:editor-clipboard -label:editor-code-actions -label:editor-color-picker -label:editor-columnselect -label:editor-commands -label:editor-comments -label:editor-contrib -label:editor-core -label:editor-drag-and-drop -label:editor-error-widget -label:editor-find -label:editor-folding -label:editor-highlight -label:editor-hover -label:editor-indent-detection -label:editor-indent-guides -label:editor-input -label:editor-input-IME -label:editor-insets -label:editor-minimap -label:editor-multicursor -label:editor-parameter-hints -label:editor-render-whitespace -label:editor-rendering -label:editor-RTL -label:editor-scrollbar -label:editor-sorting -label:editor-sticky-scroll -label:editor-symbols -label:editor-synced-region -label:editor-textbuffer -label:editor-theming -label:editor-wordnav -label:editor-wrapping -label:emmet -label:emmet-parse -label:error-list -label:extension-activation -label:extension-host -label:extension-prerelease -label:extension-recommendations -label:extensions -label:extensions-development -label:file-decorations -label:file-encoding -label:file-explorer -label:file-glob -label:file-io -label:file-nesting -label:file-watcher -label:font-rendering -label:formatting -label:getting-started -label:ghost-text -label:git -label:github -label:github-repositories -label:gpu -label:grammar -label:grid-widget -label:html -label:icon-brand -label:icons-product -label:image-preview -label:inlay-hints -label:inline-completions -label:install-update -label:intellisense-config -label:interactive-playground -label:interactive-window -label:issue-bot -label:issue-reporter -label:javascript -label:json -label:keybindings -label:keybindings-editor -label:keybindings-json -label:keyboard-layout -label:L10N -label:l10n-platform -label:label-provider -label:languages-basic -label:languages-diagnostics -label:languages-guessing -label:layout -label:lcd-text-rendering -label:list-widget -label:live-preview -label:log -label:markdown -label:marketplace -label:menus -label:merge-conflict -label:merge-editor -label:merge-editor-workbench -label:monaco-editor -label:native-file-dialog -label:network -label:notebook -label:notebook-api -label:notebook-builtin-renderers -label:notebook-cell-editor -label:notebook-celltoolbar -label:notebook-clipboard -label:notebook-commenting -label:notebook-debugging -label:notebook-diff -label:notebook-dnd -label:notebook-execution -label:notebook-find -label:notebook-folding -label:notebook-getting-started -label:notebook-globaltoolbar -label:notebook-ipynb -label:notebook-kernel -label:notebook-kernel-picker -label:notebook-language -label:notebook-layout -label:notebook-markdown -label:notebook-math -label:notebook-minimap -label:notebook-multiselect -label:notebook-output -label:notebook-perf -label:notebook-remote -label:notebook-rendering -label:notebook-serialization -label:notebook-serverless-web -label:notebook-statusbar -label:notebook-toc-outline -label:notebook-undo-redo -label:notebook-variables -label:notebook-workbench-integration -label:notebook-workflow -label:open-editors -label:opener -label:outline -label:output -label:packaging -label:perf -label:perf-bloat -label:perf-startup -label:php -label:portable-mode -label:proxy -label:quick-open -label:quick-pick -label:references-viewlet -label:release-notes -label:remote -label:remote-connection -label:remote-explorer -label:remote-tunnel -label:rename -label:runCommands -label:sandbox -label:sash-widget -label:scm -label:screencast-mode -label:search -label:search-api -label:search-editor -label:search-replace -label:semantic-tokens -label:server -label:settings-editor -label:settings-sync -label:settings-sync-server -label:shared-process -label:simple-file-dialog -label:smart-select -label:snap -label:snippets -label:splitview-widget -label:ssh -label:suggest -label:table-widget -label:tasks -label:telemetry -label:terminal -label:terminal-accessibility -label:terminal-conpty -label:terminal-editors -label:terminal-external -label:terminal-find -label:terminal-input -label:terminal-layout -label:terminal-links -label:terminal-local-echo -label:terminal-persistence -label:terminal-process -label:terminal-profiles -label:terminal-quick-fix -label:terminal-rendering -label:terminal-shell-bash -label:terminal-shell-cmd -label:terminal-shell-fish -label:terminal-shell-git-bash -label:terminal-shell-integration -label:terminal-shell-pwsh -label:terminal-shell-zsh -label:terminal-tabs -label:terminal-winpty -label:testing -label:themes -label:timeline -label:timeline-git -label:timeline-local-history -label:titlebar -label:tokenization -label:touch/pointer -label:trackpad/scroll -label:tree-views -label:tree-widget -label:typescript -label:undo-redo -label:unicode-highlight -label:uri -label:user-profiles -label:ux -label:variable-resolving -label:VIM -label:virtual-workspaces -label:vscode-website -label:vscode.dev -label:web -label:webview -label:webview-views -label:workbench-actions -label:workbench-banner -label:workbench-cli -label:workbench-diagnostics -label:workbench-dnd -label:workbench-editor-grid -label:workbench-editor-groups -label:workbench-editor-resolver -label:workbench-editors -label:workbench-electron -label:workbench-fonts -label:workbench-history -label:workbench-hot-exit -label:workbench-hover -label:workbench-launch -label:workbench-link -label:workbench-multiroot -label:workbench-notifications -label:workbench-os-integration -label:workbench-rapid-render -label:workbench-run-as-admin -label:workbench-state -label:workbench-status -label:workbench-tabs -label:workbench-touchbar -label:workbench-untitled-editors -label:workbench-views -label:workbench-welcome -label:workbench-window -label:workbench-workspace -label:workbench-zen -label:workspace-edit -label:workspace-symbols -label:workspace-trust -label:zoom -label:inline-chat -label:panel-chat -label:audio-cue -label:tasks -label:error-list -label:winget\n" + "value": "repo:microsoft/vscode assignee:@me is:open type:issue -label:\"info-needed\" -label:api -label:api-finalization -label:api-proposal -label:authentication -label:bisect-ext -label:bracket-pair-colorization -label:bracket-pair-guides -label:breadcrumbs -label:callhierarchy -label:chrome-devtools -label:cloud-changes -label:code-lens -label:command-center -label:comments -label:config -label:containers -label:context-keys -label:continue-working-on -label:css-less-scss -label:custom-editors -label:debug -label:debug-disassembly -label:dialogs -label:diff-editor -label:dropdown -label:editor-api -label:editor-autoclosing -label:editor-autoindent -label:editor-bracket-matching -label:editor-clipboard -label:editor-code-actions -label:editor-color-picker -label:editor-columnselect -label:editor-commands -label:editor-comments -label:editor-contrib -label:editor-core -label:editor-drag-and-drop -label:editor-error-widget -label:editor-find -label:editor-folding -label:editor-highlight -label:editor-hover -label:editor-indent-detection -label:editor-indent-guides -label:editor-input -label:editor-input-IME -label:editor-insets -label:editor-minimap -label:editor-multicursor -label:editor-parameter-hints -label:editor-render-whitespace -label:editor-rendering -label:editor-widgets -label:editor-RTL -label:editor-scrollbar -label:editor-sorting -label:editor-sticky-scroll -label:editor-symbols -label:editor-synced-region -label:editor-textbuffer -label:editor-theming -label:editor-wordnav -label:editor-wrapping -label:emmet -label:emmet-parse -label:error-list -label:extension-activation -label:extension-host -label:extension-prerelease -label:extension-recommendations -label:extensions -label:extensions-development -label:file-decorations -label:file-encoding -label:file-explorer -label:file-glob -label:file-io -label:file-nesting -label:file-watcher -label:font-rendering -label:formatting -label:getting-started -label:ghost-text -label:git -label:github -label:github-repositories -label:gpu -label:grammar -label:grid-widget -label:html -label:icon-brand -label:icons-product -label:image-preview -label:inlay-hints -label:inline-completions -label:install-update -label:intellisense-config -label:interactive-playground -label:interactive-window -label:issue-bot -label:issue-reporter -label:javascript -label:json -label:keybindings -label:keybindings-editor -label:keyboard-layout -label:L10N -label:l10n-platform -label:label-provider -label:languages-basic -label:languages-diagnostics -label:languages-guessing -label:layout -label:lcd-text-rendering -label:list-widget -label:live-preview -label:log -label:markdown -label:marketplace -label:menus -label:merge-conflict -label:merge-editor -label:merge-editor-workbench -label:monaco-editor -label:native-file-dialog -label:network -label:notebook -label:notebook-api -label:notebook-builtin-renderers -label:notebook-cell-editor -label:notebook-celltoolbar -label:notebook-clipboard -label:notebook-commenting -label:notebook-debugging -label:notebook-diff -label:notebook-dnd -label:notebook-execution -label:notebook-find -label:notebook-folding -label:notebook-getting-started -label:notebook-globaltoolbar -label:notebook-ipynb -label:notebook-kernel -label:notebook-kernel-picker -label:notebook-language -label:notebook-layout -label:notebook-markdown -label:notebook-math -label:notebook-minimap -label:notebook-multiselect -label:notebook-output -label:notebook-perf -label:notebook-remote -label:notebook-rendering -label:notebook-serialization -label:notebook-serverless-web -label:notebook-statusbar -label:notebook-toc-outline -label:notebook-undo-redo -label:notebook-variables -label:notebook-workbench-integration -label:notebook-workflow -label:open-editors -label:opener -label:outline -label:output -label:packaging -label:perf -label:perf-bloat -label:perf-startup -label:php -label:portable-mode -label:proxy -label:quick-open -label:quick-pick -label:references-viewlet -label:release-notes -label:remote -label:remote-connection -label:remote-explorer -label:remote-tunnel -label:rename -label:runCommands -label:sandbox -label:sash-widget -label:scm -label:screencast-mode -label:search -label:search-api -label:search-editor -label:search-replace -label:semantic-tokens -label:server -label:settings-editor -label:settings-sync -label:settings-sync-server -label:shared-process -label:simple-file-dialog -label:smart-select -label:snap -label:snippets -label:splitview-widget -label:ssh -label:suggest -label:table-widget -label:tasks -label:telemetry -label:terminal -label:terminal-accessibility -label:terminal-conpty -label:terminal-editors -label:terminal-external -label:terminal-find -label:terminal-input -label:terminal-layout -label:terminal-links -label:terminal-local-echo -label:terminal-persistence -label:terminal-process -label:terminal-profiles -label:terminal-quick-fix -label:terminal-rendering -label:terminal-shell-bash -label:terminal-shell-cmd -label:terminal-shell-fish -label:terminal-shell-git-bash -label:terminal-shell-integration -label:terminal-shell-pwsh -label:terminal-shell-zsh -label:terminal-tabs -label:testing -label:themes -label:timeline -label:timeline-git -label:timeline-local-history -label:titlebar -label:tokenization -label:touch/pointer -label:trackpad/scroll -label:tree-views -label:tree-widget -label:typescript -label:undo-redo -label:unicode-highlight -label:uri -label:user-profiles -label:ux -label:variable-resolving -label:VIM -label:virtual-workspaces -label:vscode-website -label:vscode.dev -label:web -label:webview -label:webview-views -label:workbench-actions -label:workbench-banner -label:workbench-cli -label:workbench-diagnostics -label:workbench-dnd -label:workbench-editor-grid -label:workbench-editor-groups -label:workbench-editor-resolver -label:workbench-editors -label:workbench-electron -label:workbench-fonts -label:workbench-history -label:workbench-hot-exit -label:workbench-hover -label:workbench-launch -label:workbench-link -label:workbench-multiroot -label:workbench-notifications -label:workbench-os-integration -label:workbench-rapid-render -label:workbench-run-as-admin -label:workbench-state -label:workbench-status -label:workbench-tabs -label:workbench-touchbar -label:workbench-untitled-editors -label:workbench-views -label:workbench-welcome -label:workbench-window -label:workbench-workspace -label:workbench-zen -label:workspace-edit -label:workspace-symbols -label:workspace-trust -label:zoom -label:inline-chat -label:panel-chat -label:quick-chat -label:audio-cue -label:tasks -label:error-list -label:winget\n" }, { "kind": 1, "language": "markdown", - "value": "### Missing Milestone\n" + "value": "### Missing Milestone\r\n" }, { "kind": 2, @@ -42,7 +42,7 @@ { "kind": 1, "language": "markdown", - "value": "#### Not Actionable\n" + "value": "#### Not Actionable\r\n" }, { "kind": 2, diff --git a/.vscode/settings.json b/.vscode/settings.json index 7434adcf4ae..163f114e7d7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -167,5 +167,6 @@ ], "[github-issues]": { "editor.wordWrap": "on" - } + }, + "css.format.spaceAroundSelectorSeparator": true, } diff --git a/cli/src/commands/args.rs b/cli/src/commands/args.rs index 7863635ae99..a69d021cab8 100644 --- a/cli/src/commands/args.rs +++ b/cli/src/commands/args.rs @@ -223,7 +223,7 @@ pub struct CommandShellArgs { #[clap(long, num_args = 0..=1, default_missing_value = "0")] pub on_port: Option, /// Require the given token string to be given in the handshake. - #[clap(long)] + #[clap(long, env = "VSCODE_CLI_REQUIRE_TOKEN")] pub require_token: Option, /// Optional parent process id. If provided, the server will be stopped when the process of the given pid no longer exists #[clap(long, hide = true)] diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 562ef1efa5f..1db13db8b63 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -201,7 +201,7 @@ export class ActionBar extends Disposable implements IActionRunner { } // Recompute focused item - else if (event.equals(KeyCode.Tab) || event.equals(KeyMod.Shift | KeyCode.Tab)) { + else if (event.equals(KeyCode.Tab) || event.equals(KeyMod.Shift | KeyCode.Tab) || event.equals(KeyCode.UpArrow) || event.equals(KeyCode.DownArrow) || event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow)) { this.updateFocusedItem(); } })); diff --git a/src/vs/base/browser/ui/iconLabel/iconlabel.css b/src/vs/base/browser/ui/iconLabel/iconlabel.css index c847aecee2f..47f8891703c 100644 --- a/src/vs/base/browser/ui/iconLabel/iconlabel.css +++ b/src/vs/base/browser/ui/iconLabel/iconlabel.css @@ -51,7 +51,7 @@ opacity: 0.5; } -.monaco-icon-label>.monaco-icon-label-container>.monaco-icon-suffix-container>.label-suffix { +.monaco-icon-label > .monaco-icon-label-container > .monaco-icon-suffix-container > .label-suffix { opacity: .7; white-space: pre; } diff --git a/src/vs/base/common/product.ts b/src/vs/base/common/product.ts index 3cdab02a17b..cbd573fdc72 100644 --- a/src/vs/base/common/product.ts +++ b/src/vs/base/common/product.ts @@ -40,7 +40,7 @@ export type ConfigurationSyncStore = { url: string; insidersUrl: string; stableUrl: string; - canSwitch: boolean; + canSwitch?: boolean; authenticationProviders: IStringDictionary<{ scopes: string[] }>; }; @@ -203,7 +203,7 @@ export interface IExtensionRecommendations { } export interface ISettingsEditorOpenCondition { - readonly prerelease: boolean | string; + readonly prerelease?: boolean | string; } export interface IExtensionRecommendationCondition { diff --git a/src/vs/base/parts/ipc/test/node/ipc.net.test.ts b/src/vs/base/parts/ipc/test/node/ipc.net.test.ts index 8255c780ccf..0e018300cea 100644 --- a/src/vs/base/parts/ipc/test/node/ipc.net.test.ts +++ b/src/vs/base/parts/ipc/test/node/ipc.net.test.ts @@ -571,6 +571,8 @@ flakySuite('IPC, create handle', () => { suite('WebSocketNodeSocket', () => { + const ds = ensureNoDisposablesAreLeakedInTestSuite(); + function toUint8Array(data: number[]): Uint8Array { const result = new Uint8Array(data.length); for (let i = 0; i < data.length; i++) { @@ -724,15 +726,15 @@ suite('WebSocketNodeSocket', () => { server.close(); const webSocketNodeSocket = new WebSocketNodeSocket(new NodeSocket(socket), true, null, false); - webSocketNodeSocket.onData((data) => { + ds.add(webSocketNodeSocket.onData((data) => { receivingSideOnDataCallCount++; receivingSideTotalBytes += data.byteLength; - }); + })); - webSocketNodeSocket.onClose(() => { + ds.add(webSocketNodeSocket.onClose(() => { webSocketNodeSocket.dispose(); receivingSideSocketClosedBarrier.open(); - }); + })); }); const socket = connect({ diff --git a/src/vs/base/test/browser/dom.test.ts b/src/vs/base/test/browser/dom.test.ts index 8e22994c7da..601f75d3523 100644 --- a/src/vs/base/test/browser/dom.test.ts +++ b/src/vs/base/test/browser/dom.test.ts @@ -8,6 +8,7 @@ import { $, asCssValueWithDefault, h, multibyteAwareBtoa, trackAttributes, copyA import { ensureCodeWindow, isAuxiliaryWindow, mainWindow } from 'vs/base/browser/window'; import { DeferredPromise, timeout } from 'vs/base/common/async'; import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; suite('dom', () => { test('hasClass', () => { @@ -404,4 +405,6 @@ suite('dom', () => { assert.strictEqual(count, 0); }); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/base/test/browser/formattedTextRenderer.test.ts b/src/vs/base/test/browser/formattedTextRenderer.test.ts index f5bcc1b2d5d..12acef6e7b8 100644 --- a/src/vs/base/test/browser/formattedTextRenderer.test.ts +++ b/src/vs/base/test/browser/formattedTextRenderer.test.ts @@ -6,6 +6,7 @@ import * as assert from 'assert'; import { renderFormattedText, renderText } from 'vs/base/browser/formattedTextRenderer'; import { DisposableStore } from 'vs/base/common/lifecycle'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; suite('FormattedTextRenderer', () => { const store = new DisposableStore(); @@ -127,4 +128,6 @@ suite('FormattedTextRenderer', () => { assert.strictEqual(result.children.length, 0); assert.strictEqual(result.innerHTML, '**bold**'); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/base/test/browser/iconLabels.test.ts b/src/vs/base/test/browser/iconLabels.test.ts index 292ec6b0bf8..c076d4ec38e 100644 --- a/src/vs/base/test/browser/iconLabels.test.ts +++ b/src/vs/base/test/browser/iconLabels.test.ts @@ -5,6 +5,7 @@ import * as assert from 'assert'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; suite('renderLabelWithIcons', () => { @@ -49,4 +50,6 @@ suite('renderLabelWithIcons', () => { .map(elem => elem instanceof HTMLElement ? elem.outerHTML : elem) .reduce((a, b) => a + b, ''); }; + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/base/test/browser/ui/contextview/contextview.test.ts b/src/vs/base/test/browser/ui/contextview/contextview.test.ts index 4b49df18555..c302c358937 100644 --- a/src/vs/base/test/browser/ui/contextview/contextview.test.ts +++ b/src/vs/base/test/browser/ui/contextview/contextview.test.ts @@ -5,6 +5,7 @@ import * as assert from 'assert'; import { layout, LayoutAnchorPosition } from 'vs/base/browser/ui/contextview/contextview'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; suite('Contextview', function () { @@ -25,4 +26,6 @@ suite('Contextview', function () { assert.strictEqual(layout(200, 20, { offset: 50, size: 50, position: LayoutAnchorPosition.After }), 30); assert.strictEqual(layout(200, 20, { offset: 150, size: 50, position: LayoutAnchorPosition.After }), 130); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/base/test/browser/ui/list/rangeMap.test.ts b/src/vs/base/test/browser/ui/list/rangeMap.test.ts index 0171250324b..5b3b4a6c65f 100644 --- a/src/vs/base/test/browser/ui/list/rangeMap.test.ts +++ b/src/vs/base/test/browser/ui/list/rangeMap.test.ts @@ -361,6 +361,8 @@ suite('RangeMap', () => { suite('RangeMap with top padding', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + test('empty', () => { const rangeMap = new RangeMap(10); assert.strictEqual(rangeMap.size, 10); diff --git a/src/vs/base/test/browser/ui/tree/objectTree.test.ts b/src/vs/base/test/browser/ui/tree/objectTree.test.ts index a3e39846a5b..05594bf561a 100644 --- a/src/vs/base/test/browser/ui/tree/objectTree.test.ts +++ b/src/vs/base/test/browser/ui/tree/objectTree.test.ts @@ -250,12 +250,14 @@ suite('CompressibleObjectTree', function () { disposeTemplate(): void { } } + const ds = ensureNoDisposablesAreLeakedInTestSuite(); + test('empty', function () { const container = document.createElement('div'); container.style.width = '200px'; container.style.height = '200px'; - const tree = new CompressibleObjectTree('test', container, new Delegate(), [new Renderer()]); + const tree = ds.add(new CompressibleObjectTree('test', container, new Delegate(), [new Renderer()])); tree.layout(200); assert.strictEqual(getRowsTextContent(container).length, 0); @@ -266,7 +268,7 @@ suite('CompressibleObjectTree', function () { container.style.width = '200px'; container.style.height = '200px'; - const tree = new CompressibleObjectTree('test', container, new Delegate(), [new Renderer()]); + const tree = ds.add(new CompressibleObjectTree('test', container, new Delegate(), [new Renderer()])); tree.layout(200); tree.setChildren(null, [ @@ -289,7 +291,7 @@ suite('CompressibleObjectTree', function () { container.style.width = '200px'; container.style.height = '200px'; - const tree = new CompressibleObjectTree('test', container, new Delegate(), [new Renderer()]); + const tree = ds.add(new CompressibleObjectTree('test', container, new Delegate(), [new Renderer()])); tree.layout(200); tree.setChildren(null, [ @@ -341,7 +343,7 @@ suite('CompressibleObjectTree', function () { container.style.width = '200px'; container.style.height = '200px'; - const tree = new CompressibleObjectTree('test', container, new Delegate(), [new Renderer()]); + const tree = ds.add(new CompressibleObjectTree('test', container, new Delegate(), [new Renderer()])); tree.layout(200); tree.setChildren(null, [ diff --git a/src/vs/base/test/common/assert.test.ts b/src/vs/base/test/common/assert.test.ts index a925cd0437a..ed4e60e8222 100644 --- a/src/vs/base/test/common/assert.test.ts +++ b/src/vs/base/test/common/assert.test.ts @@ -5,6 +5,7 @@ import * as assert from 'assert'; import { ok } from 'vs/base/common/assert'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; suite('Assert', () => { test('ok', () => { @@ -31,4 +32,6 @@ suite('Assert', () => { ok({}); ok(5); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/base/test/common/event.test.ts b/src/vs/base/test/common/event.test.ts index 2231acac008..df7aac4363d 100644 --- a/src/vs/base/test/common/event.test.ts +++ b/src/vs/base/test/common/event.test.ts @@ -40,11 +40,17 @@ namespace Samples { this._onDidChange.fire(value); } + dispose() { + this._onDidChange.dispose(); + } + } } suite('Event utils dispose', function () { + const ds = ensureNoDisposablesAreLeakedInTestSuite(); + let tracker = new DisposableTracker(); function assertDisposablesCount(expected: number | Array) { @@ -75,7 +81,7 @@ suite('Event utils dispose', function () { test('no leak with snapshot-utils', function () { const store = new DisposableStore(); - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const evens = Event.filter(emitter.event, n => n % 2 === 0, store); assertDisposablesCount(1); // snaphot only listen when `evens` is being listened on @@ -91,7 +97,7 @@ suite('Event utils dispose', function () { test('no leak with debounce-util', function () { const store = new DisposableStore(); - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const debounced = Event.debounce(emitter.event, (l) => 0, undefined, undefined, undefined, undefined, store); assertDisposablesCount(1); // debounce only listens when `debounce` is being listened on @@ -109,13 +115,15 @@ suite('Event utils dispose', function () { suite('Event', function () { + const ds = ensureNoDisposablesAreLeakedInTestSuite(); + const counter = new Samples.EventCounter(); setup(() => counter.reset()); test('Emitter plain', function () { - const doc = new Samples.Document3(); + const doc = ds.add(new Samples.Document3()); const subscription = doc.onDidChange(counter.onEvent, counter); @@ -133,10 +141,10 @@ suite('Event', function () { const a = (v: string) => calls.push(`a${v}`); const b = (v: string) => calls.push(`b${v}`); - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); - emitter.event(a); - emitter.event(b); + ds.add(emitter.event(a)); + ds.add(emitter.event(b)); const s2 = emitter.event(a); emitter.fire('1'); @@ -150,14 +158,14 @@ suite('Event', function () { test('Emitter, dispose listener during emission', () => { for (let keepFirstMod = 1; keepFirstMod < 4; keepFirstMod++) { - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const calls: number[] = []; - const disposables = Array.from({ length: 25 }, (_, n) => emitter.event(() => { + const disposables = Array.from({ length: 25 }, (_, n) => ds.add(emitter.event(() => { if (n % keepFirstMod === 0) { disposables[n].dispose(); } calls.push(n); - })); + }))); emitter.fire(); assert.deepStrictEqual(calls, Array.from({ length: 25 }, (_, n) => n)); @@ -165,14 +173,14 @@ suite('Event', function () { }); test('Emitter, dispose emitter during emission', () => { - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const calls: number[] = []; - const disposables = Array.from({ length: 25 }, (_, n) => emitter.event(() => { + const disposables = Array.from({ length: 25 }, (_, n) => ds.add(emitter.event(() => { if (n === 10) { emitter.dispose(); } calls.push(n); - })); + }))); emitter.fire(); disposables.forEach(d => d.dispose()); @@ -181,15 +189,15 @@ suite('Event', function () { test('Emitter, shared delivery queue', () => { const deliveryQueue = createEventDeliveryQueue(); - const emitter1 = new Emitter({ deliveryQueue }); - const emitter2 = new Emitter({ deliveryQueue }); + const emitter1 = ds.add(new Emitter({ deliveryQueue })); + const emitter2 = ds.add(new Emitter({ deliveryQueue })); const calls: string[] = []; - emitter1.event(d => { calls.push(`${d}a`); if (d === 1) { emitter2.fire(2); } }); - emitter1.event(d => { calls.push(`${d}b`); }); + ds.add(emitter1.event(d => { calls.push(`${d}a`); if (d === 1) { emitter2.fire(2); } })); + ds.add(emitter1.event(d => { calls.push(`${d}b`); })); - emitter2.event(d => { calls.push(`${d}c`); emitter1.dispose(); }); - emitter2.event(d => { calls.push(`${d}d`); }); + ds.add(emitter2.event(d => { calls.push(`${d}c`); emitter1.dispose(); })); + ds.add(emitter2.event(d => { calls.push(`${d}d`); })); emitter1.fire(1); @@ -201,13 +209,13 @@ suite('Event', function () { test('Emitter, handles removal during 3', () => { const fn1 = stub(); const fn2 = stub(); - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); - emitter.event(fn1); + ds.add(emitter.event(fn1)); const h = emitter.event(() => { h.dispose(); }); - emitter.event(fn2); + ds.add(emitter.event(fn2)); emitter.fire('foo'); assert.deepStrictEqual(fn2.args, [['foo']]); @@ -216,9 +224,9 @@ suite('Event', function () { test('Emitter, handles removal during 2', () => { const fn1 = stub(); - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); - emitter.event(fn1); + ds.add(emitter.event(fn1)); const h = emitter.event(() => { h.dispose(); }); @@ -230,7 +238,7 @@ suite('Event', function () { test('Emitter, bucket', function () { const bucket: IDisposable[] = []; - const doc = new Samples.Document3(); + const doc = ds.add(new Samples.Document3()); const subscription = doc.onDidChange(counter.onEvent, counter, bucket); doc.setText('far'); @@ -251,8 +259,8 @@ suite('Event', function () { test('Emitter, store', function () { - const bucket = new DisposableStore(); - const doc = new Samples.Document3(); + const bucket = ds.add(new DisposableStore()); + const doc = ds.add(new Samples.Document3()); const subscription = doc.onDidChange(counter.onEvent, counter, bucket); doc.setText('far'); @@ -273,16 +281,16 @@ suite('Event', function () { let firstCount = 0; let lastCount = 0; - const a = new Emitter({ + const a = ds.add(new Emitter({ onWillAddFirstListener() { firstCount += 1; }, onDidRemoveLastListener() { lastCount += 1; } - }); + })); assert.strictEqual(firstCount, 0); assert.strictEqual(lastCount, 0); - let subscription1 = a.event(function () { }); - const subscription2 = a.event(function () { }); + let subscription1 = ds.add(a.event(function () { })); + const subscription2 = ds.add(a.event(function () { })); assert.strictEqual(firstCount, 1); assert.strictEqual(lastCount, 0); @@ -294,26 +302,26 @@ suite('Event', function () { assert.strictEqual(firstCount, 1); assert.strictEqual(lastCount, 1); - subscription1 = a.event(function () { }); + subscription1 = ds.add(a.event(function () { })); assert.strictEqual(firstCount, 2); assert.strictEqual(lastCount, 1); }); test('onWillRemoveListener', () => { let count = 0; - const a = new Emitter({ + const a = ds.add(new Emitter({ onWillRemoveListener() { count += 1; } - }); + })); assert.strictEqual(count, 0); - let subscription = a.event(function () { }); + let subscription = ds.add(a.event(function () { })); assert.strictEqual(count, 0); subscription.dispose(); assert.strictEqual(count, 1); - subscription = a.event(function () { }); + subscription = ds.add(a.event(function () { })); assert.strictEqual(count, 1); }); @@ -322,15 +330,15 @@ suite('Event', function () { setUnexpectedErrorHandler(() => null); try { - const a = new Emitter(); + const a = ds.add(new Emitter()); let hit = false; - a.event(function () { + ds.add(a.event(function () { // eslint-disable-next-line no-throw-literal throw 9; - }); - a.event(function () { + })); + ds.add(a.event(function () { hit = true; - }); + })); a.fire(undefined); assert.strictEqual(hit, true); @@ -343,17 +351,17 @@ suite('Event', function () { const allError: any[] = []; - const a = new Emitter({ + const a = ds.add(new Emitter({ onListenerError(e) { allError.push(e); } - }); + })); let hit = false; - a.event(function () { + ds.add(a.event(function () { // eslint-disable-next-line no-throw-literal throw 9; - }); - a.event(function () { + })); + ds.add(a.event(function () { hit = true; - }); + })); a.fire(undefined); assert.strictEqual(hit, true); assert.deepStrictEqual(allError, [9]); @@ -367,7 +375,7 @@ suite('Event', function () { } const context = {}; - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const reg1 = emitter.event(listener, context); const reg2 = emitter.event(listener, context); @@ -395,7 +403,7 @@ suite('Event', function () { } }); - emitter.event(e => { sum = e; }); + ds.add(emitter.event(e => { sum = e; })); const p = Event.toPromise(emitter.event); @@ -433,18 +441,18 @@ suite('Event', function () { }); test('Emitter - In Order Delivery', function () { - const a = new Emitter(); + const a = ds.add(new Emitter()); const listener2Events: string[] = []; - a.event(function listener1(event) { + ds.add(a.event(function listener1(event) { if (event === 'e1') { a.fire('e2'); // assert that all events are delivered at this point assert.deepStrictEqual(listener2Events, ['e1', 'e2']); } - }); - a.event(function listener2(event) { + })); + ds.add(a.event(function listener2(event) { listener2Events.push(event); - }); + })); a.fire('e1'); // assert that all events are delivered in order @@ -452,25 +460,25 @@ suite('Event', function () { }); test('Emitter, - In Order Delivery 3x', function () { - const a = new Emitter(); + const a = ds.add(new Emitter()); const listener2Events: string[] = []; - a.event(function listener1(event) { + ds.add(a.event(function listener1(event) { if (event === 'e2') { a.fire('e3'); // assert that all events are delivered at this point assert.deepStrictEqual(listener2Events, ['e1', 'e2', 'e3']); } - }); - a.event(function listener1(event) { + })); + ds.add(a.event(function listener1(event) { if (event === 'e1') { a.fire('e2'); // assert that all events are delivered at this point assert.deepStrictEqual(listener2Events, ['e1', 'e2', 'e3']); } - }); - a.event(function listener2(event) { + })); + ds.add(a.event(function listener2(event) { listener2Events.push(event); - }); + })); a.fire('e1'); // assert that all events are delivered in order @@ -478,7 +486,7 @@ suite('Event', function () { }); test('Cannot read property \'_actual\' of undefined #142204', function () { - const e = new Emitter(); + const e = ds.add(new Emitter()); const dispo = e.event(() => { }); dispo.dispose.call(undefined); // assert that disposable can be called with this }); @@ -486,6 +494,8 @@ suite('Event', function () { suite('AsyncEmitter', function () { + const ds = ensureNoDisposablesAreLeakedInTestSuite(); + test('event has waitUntil-function', async function () { interface E extends IWaitUntil { @@ -495,11 +505,11 @@ suite('AsyncEmitter', function () { const emitter = new AsyncEmitter(); - emitter.event(e => { + ds.add(emitter.event(e => { assert.strictEqual(e.foo, true); assert.strictEqual(e.bar, 1); assert.strictEqual(typeof e.waitUntil, 'function'); - }); + })); emitter.fireAsync({ foo: true, bar: 1, }, CancellationToken.None); emitter.dispose(); @@ -515,19 +525,19 @@ suite('AsyncEmitter', function () { let globalState = 0; const emitter = new AsyncEmitter(); - emitter.event(e => { + ds.add(emitter.event(e => { e.waitUntil(timeout(10).then(_ => { assert.strictEqual(globalState, 0); globalState += 1; })); - }); + })); - emitter.event(e => { + ds.add(emitter.event(e => { e.waitUntil(timeout(1).then(_ => { assert.strictEqual(globalState, 1); globalState += 1; })); - }); + })); await emitter.fireAsync({ foo: true }, CancellationToken.None); assert.strictEqual(globalState, 2); @@ -545,7 +555,7 @@ suite('AsyncEmitter', function () { const emitter = new AsyncEmitter(); // e1 - emitter.event(e => { + ds.add(emitter.event(e => { e.waitUntil(timeout(10).then(async _ => { if (e.foo === 1) { await emitter.fireAsync({ foo: 2 }, CancellationToken.None); @@ -553,13 +563,13 @@ suite('AsyncEmitter', function () { done = true; } })); - }); + })); // e2 - emitter.event(e => { + ds.add(emitter.event(e => { events.push(e.foo); e.waitUntil(timeout(7)); - }); + })); await emitter.fireAsync({ foo: 1 }, CancellationToken.None); assert.ok(done); @@ -577,16 +587,16 @@ suite('AsyncEmitter', function () { let globalState = 0; const emitter = new AsyncEmitter(); - emitter.event(e => { + ds.add(emitter.event(e => { globalState += 1; e.waitUntil(new Promise((_r, reject) => reject(new Error()))); - }); + })); - emitter.event(e => { + ds.add(emitter.event(e => { globalState += 1; e.waitUntil(timeout(10)); e.waitUntil(timeout(20).then(() => globalState++)); // multiple `waitUntil` are supported and awaited on - }); + })); await emitter.fireAsync({ foo: true }, CancellationToken.None).then(() => { assert.strictEqual(globalState, 3); @@ -601,11 +611,13 @@ suite('AsyncEmitter', function () { suite('PausableEmitter', function () { + const ds = ensureNoDisposablesAreLeakedInTestSuite(); + test('basic', function () { const data: number[] = []; - const emitter = new PauseableEmitter(); + const emitter = ds.add(new PauseableEmitter()); - emitter.event(e => data.push(e)); + ds.add(emitter.event(e => data.push(e))); emitter.fire(1); emitter.fire(2); @@ -614,9 +626,9 @@ suite('PausableEmitter', function () { test('pause/resume - no merge', function () { const data: number[] = []; - const emitter = new PauseableEmitter(); + const emitter = ds.add(new PauseableEmitter()); - emitter.event(e => data.push(e)); + ds.add(emitter.event(e => data.push(e))); emitter.fire(1); emitter.fire(2); assert.deepStrictEqual(data, [1, 2]); @@ -634,9 +646,9 @@ suite('PausableEmitter', function () { test('pause/resume - merge', function () { const data: number[] = []; - const emitter = new PauseableEmitter({ merge: (a) => a.reduce((p, c) => p + c, 0) }); + const emitter = ds.add(new PauseableEmitter({ merge: (a) => a.reduce((p, c) => p + c, 0) })); - emitter.event(e => data.push(e)); + ds.add(emitter.event(e => data.push(e))); emitter.fire(1); emitter.fire(2); assert.deepStrictEqual(data, [1, 2]); @@ -655,9 +667,9 @@ suite('PausableEmitter', function () { test('double pause/resume', function () { const data: number[] = []; - const emitter = new PauseableEmitter(); + const emitter = ds.add(new PauseableEmitter()); - emitter.event(e => data.push(e)); + ds.add(emitter.event(e => data.push(e))); emitter.fire(1); emitter.fire(2); assert.deepStrictEqual(data, [1, 2]); @@ -680,9 +692,9 @@ suite('PausableEmitter', function () { test('resume, no pause', function () { const data: number[] = []; - const emitter = new PauseableEmitter(); + const emitter = ds.add(new PauseableEmitter()); - emitter.event(e => data.push(e)); + ds.add(emitter.event(e => data.push(e))); emitter.fire(1); emitter.fire(2); assert.deepStrictEqual(data, [1, 2]); @@ -694,20 +706,20 @@ suite('PausableEmitter', function () { test('nested pause', function () { const data: number[] = []; - const emitter = new PauseableEmitter(); + const emitter = ds.add(new PauseableEmitter()); let once = true; - emitter.event(e => { + ds.add(emitter.event(e => { data.push(e); if (once) { emitter.pause(); once = false; } - }); - emitter.event(e => { + })); + ds.add(emitter.event(e => { data.push(e); - }); + })); emitter.pause(); emitter.fire(1); @@ -727,8 +739,8 @@ suite('PausableEmitter', function () { test('empty pause with merge', function () { const data: number[] = []; - const emitter = new PauseableEmitter({ merge: a => a[0] }); - emitter.event(e => data.push(1)); + const emitter = ds.add(new PauseableEmitter({ merge: a => a[0] })); + ds.add(emitter.event(e => data.push(1))); emitter.pause(); emitter.resume(); @@ -766,12 +778,14 @@ suite('Event utils - ensureNoDisposablesAreLeakedInTestSuite', function () { suite('Event utils', () => { + const ds = ensureNoDisposablesAreLeakedInTestSuite(); + suite('EventBufferer', () => { test('should not buffer when not wrapped', () => { const bufferer = new EventBufferer(); const counter = new Samples.EventCounter(); - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const event = bufferer.wrapEvent(emitter.event); const listener = event(counter.onEvent, counter); @@ -789,7 +803,7 @@ suite('Event utils', () => { test('should buffer when wrapped', () => { const bufferer = new EventBufferer(); const counter = new Samples.EventCounter(); - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const event = bufferer.wrapEvent(emitter.event); const listener = event(counter.onEvent, counter); @@ -812,7 +826,7 @@ suite('Event utils', () => { }); test('once', () => { - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); let counter1 = 0, counter2 = 0, counter3 = 0; @@ -844,7 +858,7 @@ suite('Event utils', () => { test('should buffer events', () => { const result: number[] = []; - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const event = emitter.event; const bufferedEvent = Event.buffer(event); @@ -866,7 +880,7 @@ suite('Event utils', () => { test('should buffer events on next tick', async () => { const result: number[] = []; - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const event = emitter.event; const bufferedEvent = Event.buffer(event, true); @@ -888,7 +902,7 @@ suite('Event utils', () => { test('should fire initial buffer events', () => { const result: number[] = []; - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const event = emitter.event; const bufferedEvent = Event.buffer(event, false, [-2, -1, 0]); @@ -897,7 +911,7 @@ suite('Event utils', () => { emitter.fire(3); assert.deepStrictEqual(result, [] as number[]); - bufferedEvent(num => result.push(num)); + ds.add(bufferedEvent(num => result.push(num))); assert.deepStrictEqual(result, [-2, -1, 0, 1, 2, 3]); }); }); @@ -907,10 +921,10 @@ suite('Event utils', () => { test('works', () => { const result: number[] = []; const m = new EventMultiplexer(); - m.event(r => result.push(r)); + ds.add(m.event(r => result.push(r))); - const e1 = new Emitter(); - m.add(e1.event); + const e1 = ds.add(new Emitter()); + ds.add(m.add(e1.event)); assert.deepStrictEqual(result, []); @@ -921,10 +935,10 @@ suite('Event utils', () => { test('multiplexer dispose works', () => { const result: number[] = []; const m = new EventMultiplexer(); - m.event(r => result.push(r)); + ds.add(m.event(r => result.push(r))); - const e1 = new Emitter(); - m.add(e1.event); + const e1 = ds.add(new Emitter()); + ds.add(m.add(e1.event)); assert.deepStrictEqual(result, []); @@ -941,10 +955,10 @@ suite('Event utils', () => { test('event dispose works', () => { const result: number[] = []; const m = new EventMultiplexer(); - m.event(r => result.push(r)); + ds.add(m.event(r => result.push(r))); - const e1 = new Emitter(); - m.add(e1.event); + const e1 = ds.add(new Emitter()); + ds.add(m.add(e1.event)); assert.deepStrictEqual(result, []); @@ -961,9 +975,9 @@ suite('Event utils', () => { test('mutliplexer event dispose works', () => { const result: number[] = []; const m = new EventMultiplexer(); - m.event(r => result.push(r)); + ds.add(m.event(r => result.push(r))); - const e1 = new Emitter(); + const e1 = ds.add(new Emitter()); const l1 = m.add(e1.event); assert.deepStrictEqual(result, []); @@ -981,14 +995,14 @@ suite('Event utils', () => { test('hot start works', () => { const result: number[] = []; const m = new EventMultiplexer(); - m.event(r => result.push(r)); + ds.add(m.event(r => result.push(r))); - const e1 = new Emitter(); - m.add(e1.event); - const e2 = new Emitter(); - m.add(e2.event); - const e3 = new Emitter(); - m.add(e3.event); + const e1 = ds.add(new Emitter()); + ds.add(m.add(e1.event)); + const e2 = ds.add(new Emitter()); + ds.add(m.add(e2.event)); + const e3 = ds.add(new Emitter()); + ds.add(m.add(e3.event)); e1.fire(1); e2.fire(2); @@ -1000,14 +1014,14 @@ suite('Event utils', () => { const result: number[] = []; const m = new EventMultiplexer(); - const e1 = new Emitter(); - m.add(e1.event); - const e2 = new Emitter(); - m.add(e2.event); - const e3 = new Emitter(); - m.add(e3.event); + const e1 = ds.add(new Emitter()); + ds.add(m.add(e1.event)); + const e2 = ds.add(new Emitter()); + ds.add(m.add(e2.event)); + const e3 = ds.add(new Emitter()); + ds.add(m.add(e3.event)); - m.event(r => result.push(r)); + ds.add(m.event(r => result.push(r))); e1.fire(1); e2.fire(2); @@ -1019,18 +1033,18 @@ suite('Event utils', () => { const result: number[] = []; const m = new EventMultiplexer(); - const e1 = new Emitter(); - m.add(e1.event); - const e2 = new Emitter(); - m.add(e2.event); + const e1 = ds.add(new Emitter()); + ds.add(m.add(e1.event)); + const e2 = ds.add(new Emitter()); + ds.add(m.add(e2.event)); - m.event(r => result.push(r)); + ds.add(m.event(r => result.push(r))); e1.fire(1); e2.fire(2); - const e3 = new Emitter(); - m.add(e3.event); + const e3 = ds.add(new Emitter()); + ds.add(m.add(e3.event)); e3.fire(3); assert.deepStrictEqual(result, [1, 2, 3]); @@ -1040,17 +1054,17 @@ suite('Event utils', () => { const result: number[] = []; const m = new EventMultiplexer(); - const e1 = new Emitter(); - m.add(e1.event); - const e2 = new Emitter(); - m.add(e2.event); + const e1 = ds.add(new Emitter()); + ds.add(m.add(e1.event)); + const e2 = ds.add(new Emitter()); + ds.add(m.add(e2.event)); - m.event(r => result.push(r)); + ds.add(m.event(r => result.push(r))); e1.fire(1); e2.fire(2); - const e3 = new Emitter(); + const e3 = ds.add(new Emitter()); const l3 = m.add(e3.event); e3.fire(3); assert.deepStrictEqual(result, [1, 2, 3]); @@ -1066,22 +1080,24 @@ suite('Event utils', () => { }); suite('DynamicListEventMultiplexer', () => { + let addEmitter: Emitter; + let removeEmitter: Emitter; const recordedEvents: number[] = []; - const addEmitter = new Emitter(); - const removeEmitter = new Emitter(); class TestItem { - readonly onTestEventEmitter = new Emitter(); + readonly onTestEventEmitter = ds.add(new Emitter()); readonly onTestEvent = this.onTestEventEmitter.event; } let items: TestItem[]; let m: DynamicListEventMultiplexer; setup(() => { + addEmitter = ds.add(new Emitter()); + removeEmitter = ds.add(new Emitter()); items = [new TestItem(), new TestItem()]; for (const [i, item] of items.entries()) { - item.onTestEvent(e => `${i}:${e}`); + ds.add(item.onTestEvent(e => `${i}:${e}`)); } m = new DynamicListEventMultiplexer(items, addEmitter.event, removeEmitter.event, e => e.onTestEvent); - m.event(e => recordedEvents.push(e)); + ds.add(m.event(e => recordedEvents.push(e))); recordedEvents.length = 0; }); teardown(() => m.dispose()); @@ -1112,11 +1128,11 @@ suite('Event utils', () => { }); test('latch', () => { - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const event = Event.latch(emitter.event); const result: number[] = []; - const listener = event(num => result.push(num)); + const listener = ds.add(event(num => result.push(num))); assert.deepStrictEqual(result, []); @@ -1148,11 +1164,11 @@ suite('Event utils', () => { }); test('dispose is reentrant', () => { - const emitter = new Emitter({ + const emitter = ds.add(new Emitter({ onDidRemoveLastListener: () => { emitter.dispose(); } - }); + })); const listener = emitter.event(() => undefined); listener.dispose(); // should not crash @@ -1164,17 +1180,17 @@ suite('Event utils', () => { return new Promise(resolve => { let promise = new DeferredPromise(); - Event.fromPromise(promise.p)(e => { + ds.add(Event.fromPromise(promise.p)(e => { assert.strictEqual(e, 1); promise = new DeferredPromise(); - Event.fromPromise(promise.p)(() => { + ds.add(Event.fromPromise(promise.p)(() => { resolve(); - }); + })); promise.error(undefined); - }); + })); promise.complete(1); }); @@ -1185,16 +1201,16 @@ suite('Event utils', () => { let promise = new DeferredPromise(); promise.complete(1); - Event.fromPromise(promise.p)(e => { + ds.add(Event.fromPromise(promise.p)(e => { assert.strictEqual(e, 1); promise = new DeferredPromise(); promise.error(undefined); - Event.fromPromise(promise.p)(() => { + ds.add(Event.fromPromise(promise.p)(() => { resolve(); - }); - }); + })); + })); }); }); @@ -1202,8 +1218,8 @@ suite('Event utils', () => { suite('Relay', () => { test('should input work', () => { - const e1 = new Emitter(); - const e2 = new Emitter(); + const e1 = ds.add(new Emitter()); + const e2 = ds.add(new Emitter()); const relay = new Relay(); const result: number[] = []; @@ -1229,13 +1245,13 @@ suite('Event utils', () => { }); test('should Relay dispose work', () => { - const e1 = new Emitter(); - const e2 = new Emitter(); + const e1 = ds.add(new Emitter()); + const e2 = ds.add(new Emitter()); const relay = new Relay(); const result: number[] = []; const listener = (num: number) => result.push(num); - relay.event(listener); + ds.add(relay.event(listener)); e1.fire(1); assert.deepStrictEqual(result, []); @@ -1257,7 +1273,7 @@ suite('Event utils', () => { }); test('runAndSubscribeWithStore', () => { - const eventEmitter = new Emitter(); + const eventEmitter = ds.add(new Emitter()); const event = eventEmitter.event; let i = 0; @@ -1288,14 +1304,14 @@ suite('Event utils', () => { suite('accumulate', () => { test('should not fire after a listener is disposed with undefined or []', async () => { - const eventEmitter = new Emitter(); + const eventEmitter = ds.add(new Emitter()); const event = eventEmitter.event; const accumulated = Event.accumulate(event, 0); const calls1: number[][] = []; const calls2: number[][] = []; - const listener1 = accumulated((e) => calls1.push(e)); - accumulated((e) => calls2.push(e)); + const listener1 = ds.add(accumulated((e) => calls1.push(e))); + ds.add(accumulated((e) => calls2.push(e))); eventEmitter.fire(1); await timeout(1); @@ -1308,29 +1324,29 @@ suite('Event utils', () => { assert.deepStrictEqual(calls2, [[1]], 'should not fire after a listener is disposed with undefined or []'); }); test('should accumulate a single event', async () => { - const eventEmitter = new Emitter(); + const eventEmitter = ds.add(new Emitter()); const event = eventEmitter.event; const accumulated = Event.accumulate(event, 0); const results1 = await new Promise(r => { - accumulated(r); + ds.add(accumulated(r)); eventEmitter.fire(1); }); assert.deepStrictEqual(results1, [1]); const results2 = await new Promise(r => { - accumulated(r); + ds.add(accumulated(r)); eventEmitter.fire(2); }); assert.deepStrictEqual(results2, [2]); }); test('should accumulate multiple events', async () => { - const eventEmitter = new Emitter(); + const eventEmitter = ds.add(new Emitter()); const event = eventEmitter.event; const accumulated = Event.accumulate(event, 0); const results1 = await new Promise(r => { - accumulated(r); + ds.add(accumulated(r)); eventEmitter.fire(1); eventEmitter.fire(2); eventEmitter.fire(3); @@ -1338,7 +1354,7 @@ suite('Event utils', () => { assert.deepStrictEqual(results1, [1, 2, 3]); const results2 = await new Promise(r => { - accumulated(r); + ds.add(accumulated(r)); eventEmitter.fire(4); eventEmitter.fire(5); eventEmitter.fire(6); @@ -1351,7 +1367,7 @@ suite('Event utils', () => { suite('debounce', () => { test('simple', function (done: () => void) { - const doc = new Samples.Document3(); + const doc = ds.add(new Samples.Document3()); const onDocDidChange = Event.debounce(doc.onDidChange, (prev: string[] | undefined, cur) => { if (!prev) { @@ -1364,7 +1380,7 @@ suite('Event utils', () => { let count = 0; - onDocDidChange(keys => { + ds.add(onDocDidChange(keys => { count++; assert.ok(keys, 'was not expecting keys.'); if (count === 1) { @@ -1374,7 +1390,7 @@ suite('Event utils', () => { assert.deepStrictEqual(keys, ['4']); done(); } - }); + })); doc.setText('1'); doc.setText('2'); @@ -1383,7 +1399,7 @@ suite('Event utils', () => { test('microtask', function (done: () => void) { - const doc = new Samples.Document3(); + const doc = ds.add(new Samples.Document3()); const onDocDidChange = Event.debounce(doc.onDidChange, (prev: string[] | undefined, cur) => { if (!prev) { @@ -1396,7 +1412,7 @@ suite('Event utils', () => { let count = 0; - onDocDidChange(keys => { + ds.add(onDocDidChange(keys => { count++; assert.ok(keys, 'was not expecting keys.'); if (count === 1) { @@ -1406,7 +1422,7 @@ suite('Event utils', () => { assert.deepStrictEqual(keys, ['4']); done(); } - }); + })); doc.setText('1'); doc.setText('2'); @@ -1415,13 +1431,13 @@ suite('Event utils', () => { test('leading', async function () { - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const debounced = Event.debounce(emitter.event, (l, e) => e, 0, /*leading=*/true); let calls = 0; - debounced(() => { + ds.add(debounced(() => { calls++; - }); + })); // If the source event is fired once, the debounced (on the leading edge) event should be fired only once emitter.fire(); @@ -1431,13 +1447,13 @@ suite('Event utils', () => { }); test('leading (2)', async function () { - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const debounced = Event.debounce(emitter.event, (l, e) => e, 0, /*leading=*/true); let calls = 0; - debounced(() => { + ds.add(debounced(() => { calls++; - }); + })); // If the source event is fired multiple times, the debounced (on the leading edge) event should be fired twice emitter.fire(); @@ -1448,11 +1464,11 @@ suite('Event utils', () => { }); test('leading reset', async function () { - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const debounced = Event.debounce(emitter.event, (l, e) => l ? l + 1 : 1, 0, /*leading=*/true); const calls: number[] = []; - debounced((e) => calls.push(e)); + ds.add(debounced((e) => calls.push(e))); emitter.fire(1); emitter.fire(1); @@ -1462,11 +1478,11 @@ suite('Event utils', () => { }); test('should not flush events when a listener is disposed', async () => { - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const debounced = Event.debounce(emitter.event, (l, e) => l ? l + 1 : 1, 0); const calls: number[] = []; - const listener = debounced((e) => calls.push(e)); + const listener = ds.add(debounced((e) => calls.push(e))); emitter.fire(1); listener.dispose(); @@ -1478,11 +1494,11 @@ suite('Event utils', () => { }); test('flushOnListenerRemove - should flush events when a listener is disposed', async () => { - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const debounced = Event.debounce(emitter.event, (l, e) => l ? l + 1 : 1, 0, undefined, true); const calls: number[] = []; - const listener = debounced((e) => calls.push(e)); + const listener = ds.add(debounced((e) => calls.push(e))); emitter.fire(1); listener.dispose(); @@ -1494,11 +1510,11 @@ suite('Event utils', () => { }); test('should flush events when the emitter is disposed', async () => { - const emitter = new Emitter(); + const emitter = ds.add(new Emitter()); const debounced = Event.debounce(emitter.event, (l, e) => l ? l + 1 : 1, 0); const calls: number[] = []; - debounced((e) => calls.push(e)); + ds.add(debounced((e) => calls.push(e))); emitter.fire(1); emitter.dispose(); @@ -1509,26 +1525,17 @@ suite('Event utils', () => { }); suite('chain2', () => { - let store: DisposableStore; let em: Emitter; let calls: number[]; - teardown(() => { - store.dispose(); - }); - - ensureNoDisposablesAreLeakedInTestSuite(); - setup(() => { - store = new DisposableStore(); - em = new Emitter(); - store.add(em); + em = ds.add(new Emitter()); calls = []; }); test('maps', () => { const ev = Event.chain(em.event, $ => $.map(v => v * 2)); - store.add(ev(v => calls.push(v))); + ds.add(ev(v => calls.push(v))); em.fire(1); em.fire(2); em.fire(3); @@ -1537,7 +1544,7 @@ suite('Event utils', () => { test('filters', () => { const ev = Event.chain(em.event, $ => $.filter(v => v % 2 === 0)); - store.add(ev(v => calls.push(v))); + ds.add(ev(v => calls.push(v))); em.fire(1); em.fire(2); em.fire(3); @@ -1547,7 +1554,7 @@ suite('Event utils', () => { test('reduces', () => { const ev = Event.chain(em.event, $ => $.reduce((acc, v) => acc + v, 0)); - store.add(ev(v => calls.push(v))); + ds.add(ev(v => calls.push(v))); em.fire(1); em.fire(2); em.fire(3); @@ -1557,7 +1564,7 @@ suite('Event utils', () => { test('latches', () => { const ev = Event.chain(em.event, $ => $.latch()); - store.add(ev(v => calls.push(v))); + ds.add(ev(v => calls.push(v))); em.fire(1); em.fire(1); em.fire(2); @@ -1576,7 +1583,7 @@ suite('Event utils', () => { .latch() ); - store.add(ev(v => calls.push(v))); + ds.add(ev(v => calls.push(v))); em.fire(1); em.fire(2); em.fire(3); diff --git a/src/vs/base/test/common/filters.test.ts b/src/vs/base/test/common/filters.test.ts index c80a6f84132..df8d25f3dab 100644 --- a/src/vs/base/test/common/filters.test.ts +++ b/src/vs/base/test/common/filters.test.ts @@ -498,6 +498,11 @@ suite('Filters', () => { assertTopScore(fuzzyScore, '_lineS', 0, '_lineS', '_lines'); }); + test.skip('Bad completion ranking changes valid variable name to class name when pressing "." #187055', function () { + assertTopScore(fuzzyScore, 'a', 1, 'A', 'a'); + assertTopScore(fuzzyScore, 'theme', 1, 'Theme', 'theme'); + }); + test('HTML closing tag proposal filtered out #38880', function () { assertMatches('\t\t<', '\t\t', '^\t^\t^', fuzzyScore, { patternPos: 0 }); assertMatches('\t\t<', '\t\t', '\t\t^', fuzzyScore, { patternPos: 2 }); diff --git a/src/vs/base/test/common/history.test.ts b/src/vs/base/test/common/history.test.ts index eae79bb5afa..39143609b88 100644 --- a/src/vs/base/test/common/history.test.ts +++ b/src/vs/base/test/common/history.test.ts @@ -184,6 +184,8 @@ suite('History Navigator', () => { suite('History Navigator 2', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + test('constructor', () => { const testObject = new HistoryNavigator2(['1', '2', '3', '4']); diff --git a/src/vs/base/test/common/iconLabels.test.ts b/src/vs/base/test/common/iconLabels.test.ts index 33aee64d860..b8352069e1c 100644 --- a/src/vs/base/test/common/iconLabels.test.ts +++ b/src/vs/base/test/common/iconLabels.test.ts @@ -6,6 +6,7 @@ import * as assert from 'assert'; import { IMatch } from 'vs/base/common/filters'; import { escapeIcons, getCodiconAriaLabel, IParsedLabelWithIcons, markdownEscapeEscapedIcons, matchesFuzzyIconAware, parseLabelWithIcons, stripIcons } from 'vs/base/common/iconLabels'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; interface IIconFilter { // Returns null if word doesn't match. @@ -110,4 +111,6 @@ suite('Icon Labels', () => { assert.strictEqual(markdownEscapeEscapedIcons('$(Hello) World'), '$(Hello) World'); assert.strictEqual(markdownEscapeEscapedIcons('\\$(Hello) World'), '\\\\$(Hello) World'); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/base/test/common/lazy.test.ts b/src/vs/base/test/common/lazy.test.ts index e3a8d66459c..361e3305d43 100644 --- a/src/vs/base/test/common/lazy.test.ts +++ b/src/vs/base/test/common/lazy.test.ts @@ -5,6 +5,7 @@ import * as assert from 'assert'; import { Lazy } from 'vs/base/common/lazy'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; suite('Lazy', () => { @@ -27,4 +28,6 @@ suite('Lazy', () => { assert.strictEqual(value.hasValue, true); assert.throws(() => value.value, /\b1\b/); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/base/test/common/lifecycle.test.ts b/src/vs/base/test/common/lifecycle.test.ts index 22e8ff77e0f..103009b5219 100644 --- a/src/vs/base/test/common/lifecycle.test.ts +++ b/src/vs/base/test/common/lifecycle.test.ts @@ -13,8 +13,9 @@ class Disposable implements IDisposable { dispose() { this.isDisposed = true; } } +// Leaks are allowed here since we test lifecycle stuff: +// eslint-disable-next-line local/code-ensure-no-disposables-leak-in-test suite('Lifecycle', () => { - test('dispose single disposable', () => { const disposable = new Disposable(); @@ -129,6 +130,8 @@ suite('Lifecycle', () => { }); suite('DisposableStore', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + test('dispose should call all child disposes even if a child throws on dispose', () => { const disposedValues = new Set(); @@ -221,6 +224,8 @@ suite('DisposableStore', () => { }); suite('Reference Collection', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + class Collection extends ReferenceCollection { private _count = 0; get count() { return this._count; } diff --git a/src/vs/base/test/common/mime.test.ts b/src/vs/base/test/common/mime.test.ts index f403db8a960..fce56646ff8 100644 --- a/src/vs/base/test/common/mime.test.ts +++ b/src/vs/base/test/common/mime.test.ts @@ -5,6 +5,7 @@ import * as assert from 'assert'; import { normalizeMimeType } from 'vs/base/common/mime'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; suite('Mime', () => { @@ -16,4 +17,6 @@ suite('Mime', () => { assert.strictEqual(normalizeMimeType('Text/plain;UPPER'), 'text/plain;UPPER'); assert.strictEqual(normalizeMimeType('Text/plain;lower'), 'text/plain;lower'); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/base/test/common/objects.test.ts b/src/vs/base/test/common/objects.test.ts index 867615abce6..2b98c775baa 100644 --- a/src/vs/base/test/common/objects.test.ts +++ b/src/vs/base/test/common/objects.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import * as objects from 'vs/base/common/objects'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; const check = (one: any, other: any, msg: string) => { assert(objects.equals(one, other), msg); @@ -17,6 +18,8 @@ const checkNot = (one: any, other: any, msg: string) => { suite('Objects', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + test('equals', () => { check(null, null, 'null'); check(undefined, undefined, 'undefined'); diff --git a/src/vs/base/test/common/strings.test.ts b/src/vs/base/test/common/strings.test.ts index ad8655b153c..e986069c888 100644 --- a/src/vs/base/test/common/strings.test.ts +++ b/src/vs/base/test/common/strings.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import * as strings from 'vs/base/common/strings'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; suite('Strings', () => { test('equalsIgnoreCase', () => { @@ -510,4 +511,6 @@ suite('Strings', () => { assert.strictEqual(strings.removeAnsiEscapeCodes(`hello${sequence}world`), 'helloworld', `expect to remove ${JSON.stringify(sequence)}`); } }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/base/test/common/tfIdf.test.ts b/src/vs/base/test/common/tfIdf.test.ts index 69c094759eb..3a423f253a3 100644 --- a/src/vs/base/test/common/tfIdf.test.ts +++ b/src/vs/base/test/common/tfIdf.test.ts @@ -6,6 +6,7 @@ import * as assert from 'assert'; import { CancellationToken } from 'vs/base/common/cancellation'; import { TfIdfCalculator, TfIdfDocument, TfIdfScore } from 'vs/base/common/tfIdf'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; /** * Generates all permutations of an array. @@ -39,6 +40,7 @@ function assertScoreOrdersEqual(actualScores: TfIdfScore[], expectedScoreKeys: s } suite('TF-IDF Calculator', function () { + ensureNoDisposablesAreLeakedInTestSuite(); test('Should return no scores when no documents are given', () => { const tfidf = new TfIdfCalculator(); const scores = tfidf.calculateScores('something', CancellationToken.None); diff --git a/src/vs/base/test/node/port.test.ts b/src/vs/base/test/node/port.test.ts index 120044651b5..9230dc84684 100644 --- a/src/vs/base/test/node/port.test.ts +++ b/src/vs/base/test/node/port.test.ts @@ -6,6 +6,7 @@ import * as assert from 'assert'; import * as net from 'net'; import * as ports from 'vs/base/node/ports'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { flakySuite } from 'vs/base/test/node/testUtils'; flakySuite('Ports', () => { @@ -29,4 +30,6 @@ flakySuite('Ports', () => { }); }, err => done(err)); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/base/test/node/powershell.test.ts b/src/vs/base/test/node/powershell.test.ts index a93a88fc746..a710bb80c46 100644 --- a/src/vs/base/test/node/powershell.test.ts +++ b/src/vs/base/test/node/powershell.test.ts @@ -6,6 +6,7 @@ import * as assert from 'assert'; import * as fs from 'fs'; import * as platform from 'vs/base/common/platform'; import { enumeratePowerShellInstallations, getFirstAvailablePowerShellInstallation, IPowerShellExeDetails } from 'vs/base/node/powershell'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; function checkPath(exePath: string) { // Check to see if the path exists @@ -28,7 +29,7 @@ function checkPath(exePath: string) { if (platform.isWindows) { suite('PowerShell finder', () => { - + ensureNoDisposablesAreLeakedInTestSuite(); test('Can find first available PowerShell', async () => { const pwshExe = await getFirstAvailablePowerShellInstallation(); const exePath = pwshExe?.exePath; diff --git a/src/vs/base/test/node/unc.test.ts b/src/vs/base/test/node/unc.test.ts index 82eaf25860d..acbc3203536 100644 --- a/src/vs/base/test/node/unc.test.ts +++ b/src/vs/base/test/node/unc.test.ts @@ -5,6 +5,7 @@ import { strictEqual } from 'assert'; import { getUNCHost } from 'vs/base/node/unc'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; suite('UNC', () => { @@ -43,4 +44,6 @@ suite('UNC', () => { strictEqual(getUNCHost('\\\\.\\UNC\\localhost\\a'), 'localhost'); strictEqual(getUNCHost('\\\\?\\UNC\\localhost\\a'), 'localhost'); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/editor/browser/widget/diffEditor/diffEditor.contribution.ts b/src/vs/editor/browser/widget/diffEditor/diffEditor.contribution.ts index 986237029eb..554c842d24d 100644 --- a/src/vs/editor/browser/widget/diffEditor/diffEditor.contribution.ts +++ b/src/vs/editor/browser/widget/diffEditor/diffEditor.contribution.ts @@ -280,17 +280,6 @@ export class AccessibleDiffViewerPrev extends Action2 { export function findFocusedDiffEditor(accessor: ServicesAccessor): IDiffEditor | null { const codeEditorService = accessor.get(ICodeEditorService); const diffEditors = codeEditorService.listDiffEditors(); - const activeCodeEditor = codeEditorService.getFocusedCodeEditor() ?? codeEditorService.getActiveCodeEditor(); - if (!activeCodeEditor) { - return null; - } - - for (let i = 0, len = diffEditors.length; i < len; i++) { - const diffEditor = diffEditors[i]; - if (diffEditor.getModifiedEditor().getId() === activeCodeEditor.getId() || diffEditor.getOriginalEditor().getId() === activeCodeEditor.getId()) { - return diffEditor; - } - } const activeElement = getActiveElement(); if (activeElement) { diff --git a/src/vs/editor/browser/widget/diffEditor/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditor/diffEditorWidget.ts index 5817e88059f..3fd6e543a61 100644 --- a/src/vs/editor/browser/widget/diffEditor/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditor/diffEditorWidget.ts @@ -483,13 +483,13 @@ export class DiffEditorWidget extends DelegatingEditor implements IDiffEditor { return; } - const model = this._diffModel.get()?.model; - if (!model) { return; } + const model = this._diffModel.get(); + if (!model || !model.isDiffUpToDate.get()) { return; } this._editors.modified.executeEdits('diffEditor', [ { range: diff.modified.toExclusiveRange(), - text: model.original.getValueInRange(diff.original.toExclusiveRange()) + text: model.model.original.getValueInRange(diff.original.toExclusiveRange()) } ]); } diff --git a/src/vs/editor/common/core/offsetRange.ts b/src/vs/editor/common/core/offsetRange.ts index 5efa09faecc..e35a27c56bc 100644 --- a/src/vs/editor/common/core/offsetRange.ts +++ b/src/vs/editor/common/core/offsetRange.ts @@ -112,6 +112,12 @@ export class OffsetRange implements IOffsetRange { return undefined; } + public intersects(other: OffsetRange): boolean { + const start = Math.max(this.start, other.start); + const end = Math.min(this.endExclusive, other.endExclusive); + return start < end; + } + public intersectsOrTouches(other: OffsetRange): boolean { const start = Math.max(this.start, other.start); const end = Math.min(this.endExclusive, other.endExclusive); diff --git a/src/vs/editor/common/diff/defaultLinesDiffComputer/algorithms/diffAlgorithm.ts b/src/vs/editor/common/diff/defaultLinesDiffComputer/algorithms/diffAlgorithm.ts index 95cc0f22054..2e0840de625 100644 --- a/src/vs/editor/common/diff/defaultLinesDiffComputer/algorithms/diffAlgorithm.ts +++ b/src/vs/editor/common/diff/defaultLinesDiffComputer/algorithms/diffAlgorithm.ts @@ -125,6 +125,13 @@ export class OffsetPair { public toString(): string { return `${this.offset1} <-> ${this.offset2}`; } + + public delta(offset: number): OffsetPair { + if (offset === 0) { + return this; + } + return new OffsetPair(this.offset1 + offset, this.offset2 + offset); + } } export interface ISequence { diff --git a/src/vs/editor/common/diff/defaultLinesDiffComputer/heuristicSequenceOptimizations.ts b/src/vs/editor/common/diff/defaultLinesDiffComputer/heuristicSequenceOptimizations.ts index da23e59f332..21eebfa8e07 100644 --- a/src/vs/editor/common/diff/defaultLinesDiffComputer/heuristicSequenceOptimizations.ts +++ b/src/vs/editor/common/diff/defaultLinesDiffComputer/heuristicSequenceOptimizations.ts @@ -220,72 +220,74 @@ export function removeShortMatches(sequence1: ISequence, sequence2: ISequence, s } export function extendDiffsToEntireWordIfAppropriate(sequence1: LinesSliceCharSequence, sequence2: LinesSliceCharSequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] { + const equalMappings = SequenceDiff.invert(sequenceDiffs, sequence1.length); + const additional: SequenceDiff[] = []; - let lastModifiedWord: { added: number; deleted: number; count: number; s1Range: OffsetRange; s2Range: OffsetRange } | undefined = undefined; + let lastPoint = new OffsetPair(0, 0); - function maybePushWordToAdditional() { - if (!lastModifiedWord) { + function scanWord(pair: OffsetPair, equalMapping: SequenceDiff) { + if (pair.offset1 < lastPoint.offset1 || pair.offset2 < lastPoint.offset2) { return; } - const originalLength1 = lastModifiedWord.s1Range.length - lastModifiedWord.deleted; - const originalLength2 = lastModifiedWord.s2Range.length - lastModifiedWord.added; - if (originalLength1 !== originalLength2) { - // TODO figure out why this happens + const w1 = sequence1.findWordContaining(pair.offset1); + const w2 = sequence2.findWordContaining(pair.offset2); + if (!w1 || !w2) { + return; + } + let w = new SequenceDiff(w1, w2); + const equalPart = w.intersect(equalMapping)!; + + let equalChars1 = equalPart.seq1Range.length; + let equalChars2 = equalPart.seq2Range.length; + + // The words do not touch previous equals mappings, as we would have processed them already. + // But they might touch the next ones. + + while (equalMappings.length > 0) { + const next = equalMappings[0]; + const intersects = next.seq1Range.intersects(w1) || next.seq2Range.intersects(w2); + if (!intersects) { + break; + } + + const v1 = sequence1.findWordContaining(next.seq1Range.start); + const v2 = sequence2.findWordContaining(next.seq2Range.start); + // Because there is an intersection, we know that the words are not empty. + const v = new SequenceDiff(v1!, v2!); + const equalPart = v.intersect(next)!; + + equalChars1 += equalPart.seq1Range.length; + equalChars2 += equalPart.seq2Range.length; + + w = w.join(v); + + if (w.seq1Range.endExclusive >= next.seq1Range.endExclusive) { + // The word extends beyond the next equal mapping. + equalMappings.shift(); + } else { + break; + } } - if (Math.max(lastModifiedWord.deleted, lastModifiedWord.added) + (lastModifiedWord.count - 1) > originalLength1) { - additional.push(new SequenceDiff(lastModifiedWord.s1Range, lastModifiedWord.s2Range)); + if (equalChars1 + equalChars2 < (w.seq1Range.length + w.seq2Range.length) * 2 / 3) { + additional.push(new SequenceDiff(w1, w2)); } - lastModifiedWord = undefined; + lastPoint = w.getEndExclusives(); } - for (const s of sequenceDiffs) { - function processWord(s1Range: OffsetRange, s2Range: OffsetRange) { - if (!lastModifiedWord || !lastModifiedWord.s1Range.containsRange(s1Range) || !lastModifiedWord.s2Range.containsRange(s2Range)) { - if (lastModifiedWord && !(lastModifiedWord.s1Range.endExclusive < s1Range.start && lastModifiedWord.s2Range.endExclusive < s2Range.start)) { - const s1Added = OffsetRange.tryCreate(lastModifiedWord.s1Range.endExclusive, s1Range.start); - const s2Added = OffsetRange.tryCreate(lastModifiedWord.s2Range.endExclusive, s2Range.start); - lastModifiedWord.deleted += s1Added?.length ?? 0; - lastModifiedWord.added += s2Added?.length ?? 0; - - lastModifiedWord.s1Range = lastModifiedWord.s1Range.join(s1Range); - lastModifiedWord.s2Range = lastModifiedWord.s2Range.join(s2Range); - } else { - maybePushWordToAdditional(); - lastModifiedWord = { added: 0, deleted: 0, count: 0, s1Range: s1Range, s2Range: s2Range }; - } - } - - const changedS1 = s1Range.intersect(s.seq1Range); - const changedS2 = s2Range.intersect(s.seq2Range); - lastModifiedWord.count++; - lastModifiedWord.deleted += changedS1?.length ?? 0; - lastModifiedWord.added += changedS2?.length ?? 0; - } - - const w1Before = sequence1.findWordContaining(s.seq1Range.start - 1); - const w2Before = sequence2.findWordContaining(s.seq2Range.start - 1); - - const w1After = sequence1.findWordContaining(s.seq1Range.endExclusive); - const w2After = sequence2.findWordContaining(s.seq2Range.endExclusive); - - if (w1Before && w1After && w2Before && w2After && w1Before.equals(w1After) && w2Before.equals(w2After)) { - processWord(w1Before, w2Before); - } else { - if (w1Before && w2Before) { - processWord(w1Before, w2Before); - } - if (w1After && w2After) { - processWord(w1After, w2After); - } + while (equalMappings.length > 0) { + const next = equalMappings.shift()!; + if (next.seq1Range.isEmpty) { + continue; } + scanWord(next.getStarts(), next); + // The equal parts are not empty, so -1 gives us a character that is equal in both parts. + scanWord(next.getEndExclusives().delta(-1), next); } - maybePushWordToAdditional(); - const merged = mergeSequenceDiffs(sequenceDiffs, additional); return merged; } diff --git a/src/vs/editor/common/diff/defaultLinesDiffComputer/linesSliceCharSequence.ts b/src/vs/editor/common/diff/defaultLinesDiffComputer/linesSliceCharSequence.ts index fe408e95581..9edc63d335f 100644 --- a/src/vs/editor/common/diff/defaultLinesDiffComputer/linesSliceCharSequence.ts +++ b/src/vs/editor/common/diff/defaultLinesDiffComputer/linesSliceCharSequence.ts @@ -92,6 +92,10 @@ export class LinesSliceCharSequence implements ISequence { // don't break between \r and \n return 0; } + if (prevCategory === CharBoundaryCategory.LineBreakLF) { + // prefer the linebreak before the change + return 150; + } let score = 0; if (prevCategory !== nextCategory) { @@ -187,7 +191,7 @@ const score: Record = { [CharBoundaryCategory.WordNumber]: 0, [CharBoundaryCategory.End]: 10, [CharBoundaryCategory.Other]: 2, - [CharBoundaryCategory.Separator]: 3, + [CharBoundaryCategory.Separator]: 30, [CharBoundaryCategory.Space]: 3, [CharBoundaryCategory.LineBreakCR]: 10, [CharBoundaryCategory.LineBreakLF]: 10, diff --git a/src/vs/editor/common/services/semanticTokensProviderStyling.ts b/src/vs/editor/common/services/semanticTokensProviderStyling.ts index e08d06038bb..f248e0e23c2 100644 --- a/src/vs/editor/common/services/semanticTokensProviderStyling.ts +++ b/src/vs/editor/common/services/semanticTokensProviderStyling.ts @@ -105,21 +105,21 @@ export class SemanticTokensProviderStyling { public warnOverlappingSemanticTokens(lineNumber: number, startColumn: number): void { if (!this._hasWarnedOverlappingTokens) { this._hasWarnedOverlappingTokens = true; - console.warn(`Overlapping semantic tokens detected at lineNumber ${lineNumber}, column ${startColumn}`); + this._logService.warn(`Overlapping semantic tokens detected at lineNumber ${lineNumber}, column ${startColumn}`); } } public warnInvalidLengthSemanticTokens(lineNumber: number, startColumn: number): void { if (!this._hasWarnedInvalidLengthTokens) { this._hasWarnedInvalidLengthTokens = true; - console.warn(`Semantic token with invalid length detected at lineNumber ${lineNumber}, column ${startColumn}`); + this._logService.warn(`Semantic token with invalid length detected at lineNumber ${lineNumber}, column ${startColumn}`); } } public warnInvalidEditStart(previousResultId: string | undefined, resultId: string | undefined, editIndex: number, editStart: number, maxExpectedStart: number): void { if (!this._hasWarnedInvalidEditStart) { this._hasWarnedInvalidEditStart = true; - console.warn(`Invalid semantic tokens edit detected (previousResultId: ${previousResultId}, resultId: ${resultId}) at edit #${editIndex}: The provided start offset ${editStart} is outside the previous data (length ${maxExpectedStart}).`); + this._logService.warn(`Invalid semantic tokens edit detected (previousResultId: ${previousResultId}, resultId: ${resultId}) at edit #${editIndex}: The provided start offset ${editStart} is outside the previous data (length ${maxExpectedStart}).`); } } diff --git a/src/vs/editor/contrib/codeAction/common/types.ts b/src/vs/editor/contrib/codeAction/common/types.ts index 4f0d8e0f171..f0f753f38d6 100644 --- a/src/vs/editor/contrib/codeAction/common/types.ts +++ b/src/vs/editor/contrib/codeAction/common/types.ts @@ -127,11 +127,6 @@ export function filtersAction(filter: CodeActionFilter, action: languages.CodeAc } } - // On empty lines and selections, show only code AI code actions - if (rangeOrSelection.isEmpty() && model.getLineContent(rangeOrSelection.startLineNumber).length === 0) { - return !!action.isAI; - } - return true; } diff --git a/src/vs/editor/contrib/codelens/browser/codelensWidget.css b/src/vs/editor/contrib/codelens/browser/codelensWidget.css index ce61f837ef5..14711df31af 100644 --- a/src/vs/editor/contrib/codelens/browser/codelensWidget.css +++ b/src/vs/editor/contrib/codelens/browser/codelensWidget.css @@ -16,24 +16,24 @@ font-family: var(--vscode-editorCodeLens-fontFamily), var(--vscode-editorCodeLens-fontFamilyDefault); } -.monaco-editor .codelens-decoration>span, -.monaco-editor .codelens-decoration>a { +.monaco-editor .codelens-decoration > span, +.monaco-editor .codelens-decoration > a { user-select: none; -webkit-user-select: none; white-space: nowrap; vertical-align: sub; } -.monaco-editor .codelens-decoration>a { +.monaco-editor .codelens-decoration > a { text-decoration: none; } -.monaco-editor .codelens-decoration>a:hover { +.monaco-editor .codelens-decoration > a:hover { cursor: pointer; color: var(--vscode-editorLink-activeForeground) !important; } -.monaco-editor .codelens-decoration>a:hover .codicon { +.monaco-editor .codelens-decoration > a:hover .codicon { color: var(--vscode-editorLink-activeForeground) !important; } @@ -45,7 +45,7 @@ font-size: var(--vscode-editorCodeLens-fontSize); } -.monaco-editor .codelens-decoration>a:hover .codicon::before { +.monaco-editor .codelens-decoration > a:hover .codicon::before { cursor: pointer; } diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index a33aba3a394..c361be19543 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -911,6 +911,10 @@ export class ContentHoverWidget extends ResizableContentWidget { public goToBottom(): void { this._hover.scrollbar.setScrollPosition({ scrollTop: this._hover.scrollbar.getScrollDimensions().scrollHeight }); } + + public toggleLocked(locked: boolean): void { + this._hover.containerDomNode.classList.toggle('locked', locked); + } } export class EditorHoverStatusBar extends Disposable implements IEditorHoverStatusBar { diff --git a/src/vs/editor/contrib/hover/browser/hover.css b/src/vs/editor/contrib/hover/browser/hover.css index 34695750fd4..649c7be5a3e 100644 --- a/src/vs/editor/contrib/hover/browser/hover.css +++ b/src/vs/editor/contrib/hover/browser/hover.css @@ -14,6 +14,10 @@ border-radius: 3px; } +.monaco-editor .monaco-hover.locked { + outline: 1px solid var(--vscode-editorHoverWidget-border); +} + .monaco-editor .monaco-hover a { color: var(--vscode-textLink-foreground); } diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index fe17f36c2c0..f9d1c44c10e 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -58,6 +58,7 @@ export class ModesHoverController extends Disposable implements IEditorContribut private _hoverActivatedByColorDecoratorClick: boolean = false; private _reactToEditorMouseMoveRunner: RunOnceScheduler; private _mouseMoveEvent: IEditorMouseEvent | undefined; + private _isLocked: boolean = false; static get(editor: ICodeEditor): ModesHoverController | null { return editor.getContribution(ModesHoverController.ID); @@ -96,6 +97,7 @@ export class ModesHoverController extends Disposable implements IEditorContribut this._toUnhook.add(this._editor.onMouseUp((e: IEditorMouseEvent) => this._onEditorMouseUp(e))); this._toUnhook.add(this._editor.onMouseMove((e: IEditorMouseEvent) => this._onEditorMouseMove(e))); this._toUnhook.add(this._editor.onKeyDown((e: IKeyboardEvent) => this._onKeyDown(e))); + this._toUnhook.add(this._editor.onKeyUp((e: IKeyboardEvent) => this._onKeyUp(e))); } else { this._toUnhook.add(this._editor.onMouseMove((e: IEditorMouseEvent) => this._onEditorMouseMove(e))); this._toUnhook.add(this._editor.onKeyDown((e: IKeyboardEvent) => this._onKeyDown(e))); @@ -206,6 +208,10 @@ export class ModesHoverController extends Disposable implements IEditorContribut private _onEditorMouseMove(mouseEvent: IEditorMouseEvent): void { this._mouseMoveEvent = mouseEvent; + if (this._isLocked) { + // When the alt key is pressed, hover remains visible + return; + } if (this._contentWidget?.isFocused || this._contentWidget?.isResizing) { return; } @@ -281,6 +287,7 @@ export class ModesHoverController extends Disposable implements IEditorContribut if (!this._editor.hasModel()) { return; } + this._toggleLockedState(e.altKey); const resolvedKeyboardEvent = this._keybindingService.softDispatch(e, this._editor.getDomNode()); // If the beginning of a multi-chord keybinding is pressed, or the command aims to focus the hover, set the variable to true, otherwise false @@ -293,6 +300,17 @@ export class ModesHoverController extends Disposable implements IEditorContribut } } + private _onKeyUp(e: IKeyboardEvent): void { + this._toggleLockedState(!e.altKey); + } + + private _toggleLockedState(locked: boolean) { + if (this._isLocked !== locked) { + this._isLocked = locked; + this._contentWidget?.widget.toggleLocked(this._isLocked); + } + } + private _hideWidgets(): void { if (_sticky) { return; diff --git a/src/vs/editor/contrib/multicursor/test/browser/multicursor.test.ts b/src/vs/editor/contrib/multicursor/test/browser/multicursor.test.ts index 9d36f7ebfd8..64de23fce27 100644 --- a/src/vs/editor/contrib/multicursor/test/browser/multicursor.test.ts +++ b/src/vs/editor/contrib/multicursor/test/browser/multicursor.test.ts @@ -83,6 +83,8 @@ function fromRange(rng: Range): number[] { } suite('Multicursor selection', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + const serviceCollection = new ServiceCollection(); serviceCollection.set(IStorageService, new InMemoryStorageService()); diff --git a/src/vs/editor/contrib/suggest/browser/media/suggest.css b/src/vs/editor/contrib/suggest/browser/media/suggest.css index bac06376685..597fa5411b3 100644 --- a/src/vs/editor/contrib/suggest/browser/media/suggest.css +++ b/src/vs/editor/contrib/suggest/browser/media/suggest.css @@ -71,24 +71,24 @@ margin-right: 0.3em; } -.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row>.contents>.main>.right>.readMore, -.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row.focused.string-label>.contents>.main>.right>.readMore { +.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row > .contents > .main > .right > .readMore, +.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row.focused.string-label > .contents > .main > .right > .readMore { display: none; } -.monaco-editor .suggest-widget.with-status-bar:not(.docs-side) .monaco-list .monaco-list-row:hover>.contents>.main>.right.can-expand-details>.details-label { +.monaco-editor .suggest-widget.with-status-bar:not(.docs-side) .monaco-list .monaco-list-row:hover > .contents > .main > .right.can-expand-details > .details-label { width: 100%; } /* Styles for Message element for when widget is loading or is empty */ -.monaco-editor .suggest-widget>.message { +.monaco-editor .suggest-widget > .message { padding-left: 22px; } /** Styles for the list element **/ -.monaco-editor .suggest-widget>.tree { +.monaco-editor .suggest-widget > .tree { height: 100%; width: 100%; } @@ -120,14 +120,14 @@ color: var(--vscode-editorSuggestWidget-selectedIconForeground); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents { flex: 1; height: 100%; overflow: hidden; padding-left: 2px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main { display: flex; overflow: hidden; text-overflow: ellipsis; @@ -135,12 +135,12 @@ justify-content: space-between; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left, +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right { display: flex; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.focused)>.contents>.main .monaco-icon-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.focused) > .contents > .main .monaco-icon-label { color: var(--vscode-editorSuggestWidget-foreground); } @@ -148,48 +148,48 @@ font-weight: bold; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main .monaco-highlighted-label .highlight { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main .monaco-highlighted-label .highlight { color: var(--vscode-editorSuggestWidget-highlightForeground); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused>.contents>.main .monaco-highlighted-label .highlight { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main .monaco-highlighted-label .highlight { color: var(--vscode-editorSuggestWidget-focusHighlightForeground); } /** ReadMore Icon styles **/ -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.codicon-close, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.readMore::before { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > .header > .codicon-close, +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .readMore::before { color: inherit; opacity: 1; font-size: 14px; cursor: pointer; } -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.codicon-close { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > .header > .codicon-close { position: absolute; top: 6px; right: 2px; } -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.codicon-close:hover, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.readMore:hover { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > .header > .codicon-close:hover, +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .readMore:hover { opacity: 1; } /** signature, qualifier, type/details opacity **/ -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label { opacity: 0.7; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.signature-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .signature-label { overflow: hidden; text-overflow: ellipsis; opacity: 0.6; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.qualifier-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .qualifier-label { margin-left: 12px; opacity: 0.4; font-size: 85%; @@ -201,7 +201,7 @@ /** Type Info and icon next to the label in the focused completion item **/ -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label { font-size: 85%; margin-left: 1.1em; overflow: hidden; @@ -209,58 +209,58 @@ white-space: nowrap; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label>.monaco-tokenized-source { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label > .monaco-tokenized-source { display: inline; } /** Details: if using CompletionItem#details, show on focus **/ -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label { display: none; } -.monaco-editor .suggest-widget:not(.shows-details) .monaco-list .monaco-list-row.focused>.contents>.main>.right>.details-label { +.monaco-editor .suggest-widget:not(.shows-details) .monaco-list .monaco-list-row.focused > .contents > .main > .right > .details-label { display: inline; } /** Details: if using CompletionItemLabel#details, always show **/ -.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label)>.contents>.main>.right>.details-label, -.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused:not(.string-label)>.contents>.main>.right>.details-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label) > .contents > .main > .right > .details-label, +.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused:not(.string-label) > .contents > .main > .right > .details-label { display: inline; } /** Ellipsis on hover **/ -.monaco-editor .suggest-widget:not(.docs-side) .monaco-list .monaco-list-row.focused:hover>.contents>.main>.right.can-expand-details>.details-label { +.monaco-editor .suggest-widget:not(.docs-side) .monaco-list .monaco-list-row.focused:hover > .contents > .main > .right.can-expand-details > .details-label { width: calc(100% - 26px); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left { flex-shrink: 1; flex-grow: 1; overflow: hidden; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.monaco-icon-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .monaco-icon-label { flex-shrink: 0; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label)>.contents>.main>.left>.monaco-icon-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label) > .contents > .main > .left > .monaco-icon-label { max-width: 100%; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label>.contents>.main>.left>.monaco-icon-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label > .contents > .main > .left > .monaco-icon-label { flex-shrink: 1; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right { overflow: hidden; flex-shrink: 4; max-width: 70%; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.readMore { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .readMore { display: inline-block; position: absolute; right: 10px; @@ -271,23 +271,23 @@ /** Do NOT display ReadMore when docs is side/below **/ -.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row>.contents>.main>.right>.readMore { +.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row > .contents > .main > .right > .readMore { display: none !important; } /** Do NOT display ReadMore when using plain CompletionItemLabel (details/documentation might not be resolved) **/ -.monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label>.contents>.main>.right>.readMore { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label > .contents > .main > .right > .readMore { display: none; } /** Focused item can show ReadMore, but can't when docs is side/below **/ -.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused.string-label>.contents>.main>.right>.readMore { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused.string-label > .contents > .main > .right > .readMore { display: inline-block; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused:hover>.contents>.main>.right>.readMore { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused:hover > .contents > .main > .right > .readMore { visibility: visible; } @@ -298,7 +298,7 @@ text-decoration: unset; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated>.monaco-icon-label-container>.monaco-icon-name-container { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated > .monaco-icon-label-container > .monaco-icon-name-container { text-decoration: line-through; } @@ -372,17 +372,17 @@ display: none; } -.monaco-editor .suggest-details>.monaco-scrollable-element { +.monaco-editor .suggest-details > .monaco-scrollable-element { flex: 1; } -.monaco-editor .suggest-details>.monaco-scrollable-element>.body { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body { box-sizing: border-box; height: 100%; width: 100%; } -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.type { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > .header > .type { flex: 2; overflow: hidden; text-overflow: ellipsis; @@ -392,55 +392,55 @@ padding: 4px 0 12px 5px; } -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.type.auto-wrap { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > .header > .type.auto-wrap { white-space: normal; word-break: break-all; } -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > .docs { margin: 0; padding: 4px 5px; white-space: pre-wrap; } -.monaco-editor .suggest-details.no-type>.monaco-scrollable-element>.body>.docs { +.monaco-editor .suggest-details.no-type > .monaco-scrollable-element > .body > .docs { margin-right: 24px; overflow: hidden; } -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > .docs.markdown-docs { padding: 0; white-space: initial; min-height: calc(1rem + 8px); } -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>div, -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>span:not(:empty) { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > .docs.markdown-docs > div, +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > .docs.markdown-docs > span:not(:empty) { padding: 4px 5px; } -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>div>p:first-child { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > .docs.markdown-docs > div > p:first-child { margin-top: 0; } -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>div>p:last-child { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > .docs.markdown-docs > div > p:last-child { margin-bottom: 0; } -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs .monaco-tokenized-source { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > .docs.markdown-docs .monaco-tokenized-source { white-space: pre; } -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs .code { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > .docs .code { white-space: pre-wrap; word-wrap: break-word; } -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs .codicon { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > .docs.markdown-docs .codicon { vertical-align: sub; } -.monaco-editor .suggest-details>.monaco-scrollable-element>.body>p:empty { +.monaco-editor .suggest-details > .monaco-scrollable-element > .body > p:empty { display: none; } diff --git a/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts b/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts index 525af0230a0..f7bd8e2eede 100644 --- a/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts +++ b/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts @@ -253,9 +253,10 @@ function computeOccurencesMultiModel(registry: LanguageFeatureRegistry { +registerModelAndPositionCommand('_executeDocumentHighlights', async (accessor, model, position) => { const languageFeaturesService = accessor.get(ILanguageFeaturesService); - return getOccurrencesAtPosition(languageFeaturesService.documentHighlightProvider, model, position, CancellationToken.None); + const map = await getOccurrencesAtPosition(languageFeaturesService.documentHighlightProvider, model, position, CancellationToken.None); + return map?.get(model.uri); }); class WordHighlighter { diff --git a/src/vs/editor/standalone/browser/standalone-tokens.css b/src/vs/editor/standalone/browser/standalone-tokens.css index 0df4a9bac81..1fc85078f9e 100644 --- a/src/vs/editor/standalone/browser/standalone-tokens.css +++ b/src/vs/editor/standalone/browser/standalone-tokens.css @@ -37,14 +37,19 @@ clip-path: inset(50%); } -/*.monaco-editor.vs [tabindex="0"]:focus { - outline: 1px solid rgba(0, 122, 204, 0.4); +.monaco-editor, .monaco-diff-editor .synthetic-focus, +.monaco-editor, .monaco-diff-editor [tabindex="0"]:focus, +.monaco-editor, .monaco-diff-editor [tabindex="-1"]:focus, +.monaco-editor, .monaco-diff-editor button:focus, +.monaco-editor, .monaco-diff-editor input[type=button]:focus, +.monaco-editor, .monaco-diff-editor input[type=checkbox]:focus, +.monaco-editor, .monaco-diff-editor input[type=search]:focus, +.monaco-editor, .monaco-diff-editor input[type=text]:focus, +.monaco-editor, .monaco-diff-editor select:focus, +.monaco-editor, .monaco-diff-editor textarea:focus { + outline-width: 1px; + outline-style: solid; outline-offset: -1px; - opacity: 1 !important; + outline-color: var(--vscode-focusBorder); + opacity: 1 } - -.monaco-editor.vs-dark [tabindex="0"]:focus { - outline: 1px solid rgba(14, 99, 156, 0.6); - outline-offset: -1px; - opacity: 1 !important; -}*/ diff --git a/src/vs/editor/test/node/diffing/fixtures/class-replacement/advanced.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/class-replacement/advanced.expected.diff.json index 5cbd3c45666..3e4c772917f 100644 --- a/src/vs/editor/test/node/diffing/fixtures/class-replacement/advanced.expected.diff.json +++ b/src/vs/editor/test/node/diffing/fixtures/class-replacement/advanced.expected.diff.json @@ -23,8 +23,8 @@ "modifiedRange": "[39,40)", "innerChanges": [ { - "originalRange": "[63,9 -> 63,43]", - "modifiedRange": "[39,9 -> 39,38]" + "originalRange": "[63,9 -> 63,48]", + "modifiedRange": "[39,9 -> 39,43]" }, { "originalRange": "[64,1 -> 72,1]", diff --git a/src/vs/editor/test/node/diffing/fixtures/method-splitting/advanced.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/method-splitting/advanced.expected.diff.json index ca938c66689..b1de25a5907 100644 --- a/src/vs/editor/test/node/diffing/fixtures/method-splitting/advanced.expected.diff.json +++ b/src/vs/editor/test/node/diffing/fixtures/method-splitting/advanced.expected.diff.json @@ -21,8 +21,12 @@ "modifiedRange": "[7,76 -> 7,80]" }, { - "originalRange": "[12,153 -> 12,155 EOL]", - "modifiedRange": "[7,157 -> 8,1 EOL]" + "originalRange": "[12,153 -> 12,153]", + "modifiedRange": "[7,157 -> 7,181]" + }, + { + "originalRange": "[13,1 -> 13,1]", + "modifiedRange": "[8,1 -> 9,1]" }, { "originalRange": "[13,31 -> 13,31]", diff --git a/src/vs/editor/test/node/diffing/fixtures/penalize-fragmentation/advanced.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/penalize-fragmentation/advanced.expected.diff.json index 7fee9a6d76d..bf0c792814a 100644 --- a/src/vs/editor/test/node/diffing/fixtures/penalize-fragmentation/advanced.expected.diff.json +++ b/src/vs/editor/test/node/diffing/fixtures/penalize-fragmentation/advanced.expected.diff.json @@ -21,8 +21,8 @@ "modifiedRange": "[2,17 -> 2,17]" }, { - "originalRange": "[1,72 -> 1,73]", - "modifiedRange": "[2,48 -> 2,59]" + "originalRange": "[1,72 -> 1,84]", + "modifiedRange": "[2,48 -> 2,70]" } ] } diff --git a/src/vs/editor/test/node/diffing/fixtures/shifting-parameters/1.tst b/src/vs/editor/test/node/diffing/fixtures/shifting-parameters/1.tst new file mode 100644 index 00000000000..4e4a1168350 --- /dev/null +++ b/src/vs/editor/test/node/diffing/fixtures/shifting-parameters/1.tst @@ -0,0 +1 @@ +function x(alignments: RangeMapping[]): x[] { } diff --git a/src/vs/editor/test/node/diffing/fixtures/shifting-parameters/2.tst b/src/vs/editor/test/node/diffing/fixtures/shifting-parameters/2.tst new file mode 100644 index 00000000000..3bdfadaa26c --- /dev/null +++ b/src/vs/editor/test/node/diffing/fixtures/shifting-parameters/2.tst @@ -0,0 +1 @@ +function x(alignments: RangeMapping[], originalLines: string[], modifiedLines: string[]): x[] { } diff --git a/src/vs/editor/test/node/diffing/fixtures/shifting-parameters/advanced.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/shifting-parameters/advanced.expected.diff.json new file mode 100644 index 00000000000..3e860d858f8 --- /dev/null +++ b/src/vs/editor/test/node/diffing/fixtures/shifting-parameters/advanced.expected.diff.json @@ -0,0 +1,22 @@ +{ + "original": { + "content": "function x(alignments: RangeMapping[]): x[] { }\n", + "fileName": "./1.tst" + }, + "modified": { + "content": "function x(alignments: RangeMapping[], originalLines: string[], modifiedLines: string[]): x[] { }\n", + "fileName": "./2.tst" + }, + "diffs": [ + { + "originalRange": "[1,2)", + "modifiedRange": "[1,2)", + "innerChanges": [ + { + "originalRange": "[1,38 -> 1,38]", + "modifiedRange": "[1,38 -> 1,88]" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/shifting-parameters/legacy.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/shifting-parameters/legacy.expected.diff.json new file mode 100644 index 00000000000..3e860d858f8 --- /dev/null +++ b/src/vs/editor/test/node/diffing/fixtures/shifting-parameters/legacy.expected.diff.json @@ -0,0 +1,22 @@ +{ + "original": { + "content": "function x(alignments: RangeMapping[]): x[] { }\n", + "fileName": "./1.tst" + }, + "modified": { + "content": "function x(alignments: RangeMapping[], originalLines: string[], modifiedLines: string[]): x[] { }\n", + "fileName": "./2.tst" + }, + "diffs": [ + { + "originalRange": "[1,2)", + "modifiedRange": "[1,2)", + "innerChanges": [ + { + "originalRange": "[1,38 -> 1,38]", + "modifiedRange": "[1,38 -> 1,88]" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/ts-confusing-2/advanced.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/ts-confusing-2/advanced.expected.diff.json index dea51256ca6..e5ad584f33e 100644 --- a/src/vs/editor/test/node/diffing/fixtures/ts-confusing-2/advanced.expected.diff.json +++ b/src/vs/editor/test/node/diffing/fixtures/ts-confusing-2/advanced.expected.diff.json @@ -75,12 +75,12 @@ "modifiedRange": "[23,25)", "innerChanges": [ { - "originalRange": "[25,9 -> 26,18]", + "originalRange": "[25,9 -> 26,13]", "modifiedRange": "[23,9 -> 23,18]" }, { - "originalRange": "[26,22 -> 26,27]", - "modifiedRange": "[23,22 -> 23,23]" + "originalRange": "[26,22 -> 26,32]", + "modifiedRange": "[23,22 -> 23,28]" }, { "originalRange": "[27,1 -> 27,1]", diff --git a/src/vs/editor/test/node/diffing/fixtures/ts-confusing/advanced.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/ts-confusing/advanced.expected.diff.json index ae0eb5c7342..e9ee88d0a75 100644 --- a/src/vs/editor/test/node/diffing/fixtures/ts-confusing/advanced.expected.diff.json +++ b/src/vs/editor/test/node/diffing/fixtures/ts-confusing/advanced.expected.diff.json @@ -31,8 +31,8 @@ "modifiedRange": "[11,17 -> 11,17]" }, { - "originalRange": "[10,72 -> 10,73]", - "modifiedRange": "[11,48 -> 11,59]" + "originalRange": "[10,72 -> 10,84]", + "modifiedRange": "[11,48 -> 11,70]" } ] }, diff --git a/src/vs/editor/test/node/diffing/fixtures/word-shared-letters/advanced.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/word-shared-letters/advanced.expected.diff.json index 23feeaa2119..7d964a94419 100644 --- a/src/vs/editor/test/node/diffing/fixtures/word-shared-letters/advanced.expected.diff.json +++ b/src/vs/editor/test/node/diffing/fixtures/word-shared-letters/advanced.expected.diff.json @@ -83,8 +83,12 @@ "modifiedRange": "[43,44)", "innerChanges": [ { - "originalRange": "[43,5 -> 43,16 EOL]", - "modifiedRange": "[43,5 -> 43,11 EOL]" + "originalRange": "[43,8 -> 43,11]", + "modifiedRange": "[43,8 -> 43,8]" + }, + { + "originalRange": "[43,14 -> 43,16 EOL]", + "modifiedRange": "[43,11 -> 43,11 EOL]" } ] }, @@ -108,7 +112,7 @@ "innerChanges": [ { "originalRange": "[53,8 -> 53,17]", - "modifiedRange": "[53,8 -> 53,31]" + "modifiedRange": "[53,8 -> 53,28]" } ] } diff --git a/src/vs/platform/dialogs/test/common/dialog.test.ts b/src/vs/platform/dialogs/test/common/dialog.test.ts index 4455350a45d..1c5db7e80b8 100644 --- a/src/vs/platform/dialogs/test/common/dialog.test.ts +++ b/src/vs/platform/dialogs/test/common/dialog.test.ts @@ -5,6 +5,7 @@ import { deepEqual } from 'assert'; import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { IMassagedMessageBoxOptions, massageMessageBoxOptions } from 'vs/platform/dialogs/common/dialogs'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -139,4 +140,6 @@ suite('Dialog', () => { assertOptions(fourButtonNegativeCancel, ['4', '3', '2', '1'], 3, -1, [3, 2, 1, 0]); } }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/platform/environment/test/node/argv.test.ts b/src/vs/platform/environment/test/node/argv.test.ts index e3f75f2cde3..a188b52b711 100644 --- a/src/vs/platform/environment/test/node/argv.test.ts +++ b/src/vs/platform/environment/test/node/argv.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { formatOptions, Option, OptionDescriptions, Subcommand, parseArgs, ErrorReporter } from 'vs/platform/environment/node/argv'; import { addArg } from 'vs/platform/environment/node/argvHelper'; @@ -81,6 +82,8 @@ suite('formatOptions', () => { ' A test command' ]); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); suite('parseArgs', () => { @@ -156,4 +159,6 @@ suite('parseArgs', () => { [] ); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/platform/environment/test/node/userDataPath.test.ts b/src/vs/platform/environment/test/node/userDataPath.test.ts index f92f1808481..644260cff8f 100644 --- a/src/vs/platform/environment/test/node/userDataPath.test.ts +++ b/src/vs/platform/environment/test/node/userDataPath.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { OPTIONS, parseArgs } from 'vs/platform/environment/node/argv'; import { getUserDataPath } from 'vs/platform/environment/node/userDataPath'; import product from 'vs/platform/product/common/product'; @@ -57,4 +58,6 @@ suite('User data path', () => { } } }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/platform/extensionManagement/test/common/configRemotes.test.ts b/src/vs/platform/extensionManagement/test/common/configRemotes.test.ts index c5ed11d8e1b..e27bb5a488a 100644 --- a/src/vs/platform/extensionManagement/test/common/configRemotes.test.ts +++ b/src/vs/platform/extensionManagement/test/common/configRemotes.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { getDomainsOfRemotes, getRemotes } from 'vs/platform/extensionManagement/common/configRemotes'; suite('Config Remotes', () => { @@ -127,4 +128,6 @@ suite('Config Remotes', () => { fetch = +refs/heads/*:refs/remotes/origin/* `; } + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts b/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts index 8994ead0bf4..9e72c1c174a 100644 --- a/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts +++ b/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts @@ -348,6 +348,8 @@ suite('NativeExtensionsScanerService Test', () => { suite('ExtensionScannerInput', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + test('compare inputs - location', () => { const anInput = (location: URI, mtime: number | undefined) => new ExtensionScannerInput(location, mtime, undefined, undefined, false, undefined, ExtensionType.User, true, true, '1.1.1', undefined, undefined, true, undefined, {}); diff --git a/src/vs/platform/telemetry/test/browser/telemetryService.test.ts b/src/vs/platform/telemetry/test/browser/telemetryService.test.ts index f20eb00d58a..8524e9a6996 100644 --- a/src/vs/platform/telemetry/test/browser/telemetryService.test.ts +++ b/src/vs/platform/telemetry/test/browser/telemetryService.test.ts @@ -8,6 +8,7 @@ import * as sinonTest from 'sinon-test'; import { mainWindow } from 'vs/base/browser/window'; import * as Errors from 'vs/base/common/errors'; import { Emitter } from 'vs/base/common/event'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -741,4 +742,6 @@ suite('TelemetryService', () => { service.dispose(); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index c7ecd0485b4..303c4577fa6 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -88,9 +88,10 @@ export interface IColorRegistry { * Register a color to the registry. * @param id The color id as used in theme description files * @param defaults The default values + * @param needsTransparency Whether the color requires transparency * @description the description */ - registerColor(id: string, defaults: ColorDefaults, description: string): ColorIdentifier; + registerColor(id: string, defaults: ColorDefaults, description: string, needsTransparency?: boolean): ColorIdentifier; /** * Register a color to the registry. @@ -139,6 +140,10 @@ class ColorRegistry implements IColorRegistry { if (deprecationMessage) { propertySchema.deprecationMessage = deprecationMessage; } + if (needsTransparency) { + propertySchema.pattern = '^#(?:(?[0-9a-fA-f]{3}[0-9a-eA-E])|(?:[0-9a-fA-F]{6}(?:(?![fF]{2})(?:[0-9a-fA-F]{2}))))?$'; + propertySchema.patternErrorMessage = 'This color must be transparent or it will obscure content'; + } this.colorSchema.properties[id] = propertySchema; this.colorReferenceSchema.enum.push(id); this.colorReferenceSchema.enumDescriptions.push(description); diff --git a/src/vs/platform/undoRedo/test/common/undoRedoService.test.ts b/src/vs/platform/undoRedo/test/common/undoRedoService.test.ts index 88fa11a3a87..27d69e4e5ac 100644 --- a/src/vs/platform/undoRedo/test/common/undoRedoService.test.ts +++ b/src/vs/platform/undoRedo/test/common/undoRedoService.test.ts @@ -6,6 +6,7 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; import { mock } from 'vs/base/test/common/mock'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { IDialogService, IPrompt } from 'vs/platform/dialogs/common/dialogs'; import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService'; import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; @@ -226,4 +227,5 @@ suite('UndoRedoService', () => { assert.strictEqual(UndoRedoGroup.None.nextOrder(), 0); }); + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/platform/userData/test/browser/fileUserDataProvider.test.ts b/src/vs/platform/userData/test/browser/fileUserDataProvider.test.ts index ef65f7c57e5..eeeb2486c46 100644 --- a/src/vs/platform/userData/test/browser/fileUserDataProvider.test.ts +++ b/src/vs/platform/userData/test/browser/fileUserDataProvider.test.ts @@ -4,25 +4,25 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { IFileService, FileChangeType, IFileChange, IFileSystemProviderWithFileReadWriteCapability, IStat, FileType, FileSystemProviderCapabilities, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileOpenOptions, IFileSystemProviderWithFileReadStreamCapability, IFileReadStreamOptions } from 'vs/platform/files/common/files'; -import { FileService } from 'vs/platform/files/common/fileService'; -import { NullLogService } from 'vs/platform/log/common/log'; -import { Schemas } from 'vs/base/common/network'; -import { URI } from 'vs/base/common/uri'; -import { FileUserDataProvider } from 'vs/platform/userData/common/fileUserDataProvider'; -import { dirname, isEqual, joinPath } from 'vs/base/common/resources'; import { VSBuffer } from 'vs/base/common/buffer'; -import { DisposableStore, IDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { Emitter, Event } from 'vs/base/common/event'; -import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider'; -import { AbstractNativeEnvironmentService } from 'vs/platform/environment/common/environmentService'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import product from 'vs/platform/product/common/product'; -import { IUserDataProfilesService, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; -import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; -import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { Schemas } from 'vs/base/common/network'; +import { dirname, isEqual, joinPath } from 'vs/base/common/resources'; import { ReadableStreamEvents } from 'vs/base/common/stream'; +import { URI } from 'vs/base/common/uri'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { AbstractNativeEnvironmentService } from 'vs/platform/environment/common/environmentService'; +import { FileService } from 'vs/platform/files/common/fileService'; +import { FileChangeType, FileSystemProviderCapabilities, FileType, IFileChange, IFileOpenOptions, IFileReadStreamOptions, IFileService, IFileSystemProviderWithFileReadStreamCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithOpenReadWriteCloseCapability, IStat } from 'vs/platform/files/common/files'; +import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider'; +import { NullLogService } from 'vs/platform/log/common/log'; +import product from 'vs/platform/product/common/product'; +import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; +import { FileUserDataProvider } from 'vs/platform/userData/common/fileUserDataProvider'; +import { IUserDataProfilesService, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; const ROOT = URI.file('tests').with({ scheme: 'vscode-tests' }); @@ -315,7 +315,7 @@ class TestFileSystemProvider implements IFileSystemProviderWithFileReadWriteCapa suite('FileUserDataProvider - Watching', () => { let testObject: FileUserDataProvider; - const disposables = new DisposableStore(); + const disposables = ensureNoDisposablesAreLeakedInTestSuite(); const rootFileResource = joinPath(ROOT, 'User'); const rootUserDataResource = rootFileResource.with({ scheme: Schemas.vscodeUserData }); @@ -332,8 +332,6 @@ suite('FileUserDataProvider - Watching', () => { testObject = disposables.add(new FileUserDataProvider(rootFileResource.scheme, new TestFileSystemProvider(fileEventEmitter.event), Schemas.vscodeUserData, userDataProfilesService, uriIdentityService, new NullLogService())); }); - teardown(() => disposables.clear()); - test('file added change event', done => { disposables.add(testObject.watch(rootUserDataResource, { excludes: [], recursive: false })); const expected = joinPath(rootUserDataResource, 'settings.json'); @@ -427,7 +425,7 @@ suite('FileUserDataProvider - Watching', () => { test('event is not triggered if not watched', async () => { const target = joinPath(rootFileResource, 'settings.json'); let triggered = false; - testObject.onDidChangeFile(() => triggered = true); + disposables.add(testObject.onDidChangeFile(() => triggered = true)); fileEventEmitter.fire([{ resource: target, type: FileChangeType.DELETED @@ -441,7 +439,7 @@ suite('FileUserDataProvider - Watching', () => { disposables.add(testObject.watch(rootUserDataResource, { excludes: [], recursive: false })); const target = joinPath(dirname(rootFileResource), 'settings.json'); let triggered = false; - testObject.onDidChangeFile(() => triggered = true); + disposables.add(testObject.onDidChangeFile(() => triggered = true)); fileEventEmitter.fire([{ resource: target, type: FileChangeType.DELETED diff --git a/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts b/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts index bc90fb28b24..db83d62e163 100644 --- a/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts +++ b/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts @@ -417,6 +417,9 @@ suite('UserDataSyncRequestsSession', () => { async loadCertificates() { return []; } }; + + ensureNoDisposablesAreLeakedInTestSuite(); + test('too many requests are thrown when limit exceeded', async () => { const testObject = new RequestsSession(1, 500, requestService, new NullLogService()); await testObject.request('url', {}, CancellationToken.None); diff --git a/src/vs/platform/windows/electron-main/windowImpl.ts b/src/vs/platform/windows/electron-main/windowImpl.ts index b68fb6ebef1..36f9a65833f 100644 --- a/src/vs/platform/windows/electron-main/windowImpl.ts +++ b/src/vs/platform/windows/electron-main/windowImpl.ts @@ -839,7 +839,7 @@ export class CodeWindow extends BaseWindow implements ICodeWindow { private async destroyWindow(reopen: boolean, skipRestoreEditors: boolean): Promise { const workspace = this._config?.workspace; - // check to discard editor state first + // check to discard editor state first if (skipRestoreEditors && workspace) { try { const workspaceStorage = this.storageMainService.workspaceStorage(workspace); @@ -854,37 +854,41 @@ export class CodeWindow extends BaseWindow implements ICodeWindow { // 'close' event will not be fired on destroy(), so signal crash via explicit event this._onDidDestroy.fire(); - // make sure to destroy the window as its renderer process is gone - this._win?.destroy(); + try { + // ask the windows service to open a new fresh window if specified + if (reopen && this._config) { - // ask the windows service to open a new fresh window if specified - if (reopen && this._config) { + // We have to reconstruct a openable from the current workspace + let uriToOpen: IWorkspaceToOpen | IFolderToOpen | undefined = undefined; + let forceEmpty = undefined; + if (isSingleFolderWorkspaceIdentifier(workspace)) { + uriToOpen = { folderUri: workspace.uri }; + } else if (isWorkspaceIdentifier(workspace)) { + uriToOpen = { workspaceUri: workspace.configPath }; + } else { + forceEmpty = true; + } - // We have to reconstruct a openable from the current workspace - let uriToOpen: IWorkspaceToOpen | IFolderToOpen | undefined = undefined; - let forceEmpty = undefined; - if (isSingleFolderWorkspaceIdentifier(workspace)) { - uriToOpen = { folderUri: workspace.uri }; - } else if (isWorkspaceIdentifier(workspace)) { - uriToOpen = { workspaceUri: workspace.configPath }; - } else { - forceEmpty = true; + // Delegate to windows service + const window = firstOrDefault(await this.windowsMainService.open({ + context: OpenContext.API, + userEnv: this._config.userEnv, + cli: { + ...this.environmentMainService.args, + _: [] // we pass in the workspace to open explicitly via `urisToOpen` + }, + urisToOpen: uriToOpen ? [uriToOpen] : undefined, + forceEmpty, + forceNewWindow: true, + remoteAuthority: this.remoteAuthority + })); + window?.focus(); } - - // Delegate to windows service - const window = firstOrDefault(await this.windowsMainService.open({ - context: OpenContext.API, - userEnv: this._config.userEnv, - cli: { - ...this.environmentMainService.args, - _: [] // we pass in the workspace to open explicitly via `urisToOpen` - }, - urisToOpen: uriToOpen ? [uriToOpen] : undefined, - forceEmpty, - forceNewWindow: true, - remoteAuthority: this.remoteAuthority - })); - window?.focus(); + } finally { + // make sure to destroy the window as its renderer process is gone. do this + // after the code for reopening the window, to prevent the entire application + // from quitting when the last window closes as a result. + this._win?.destroy(); } } diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index 576725137cd..3053b0782ee 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -1495,7 +1495,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic const disposables = new DisposableStore(); disposables.add(createdWindow.onDidSignalReady(() => this._onDidSignalReadyWindow.fire(createdWindow))); disposables.add(Event.once(createdWindow.onDidClose)(() => this.onWindowClosed(createdWindow, disposables))); - disposables.add(Event.once(createdWindow.onDidDestroy)(() => this._onDidDestroyWindow.fire(createdWindow))); + disposables.add(Event.once(createdWindow.onDidDestroy)(() => this.onWindowDestroyed(createdWindow))); disposables.add(createdWindow.onDidMaximize(() => this._onDidMaximizeWindow.fire(createdWindow))); disposables.add(createdWindow.onDidUnmaximize(() => this._onDidUnmaximizeWindow.fire(createdWindow))); disposables.add(createdWindow.onDidTriggerSystemContextMenu(({ x, y }) => this._onDidTriggerSystemContextMenu.fire({ window: createdWindow, x, y }))); @@ -1627,6 +1627,15 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic disposables.dispose(); } + private onWindowDestroyed(window: ICodeWindow): void { + + // Remove from our list so that Electron can clean it up + this.windows.delete(window.id); + + // Emit + this._onDidDestroyWindow.fire(window); + } + getFocusedWindow(): ICodeWindow | undefined { const window = BrowserWindow.getFocusedWindow(); if (window) { diff --git a/src/vs/platform/workspaces/test/common/workspaces.test.ts b/src/vs/platform/workspaces/test/common/workspaces.test.ts index 374ac0657f2..a1f2f262d00 100644 --- a/src/vs/platform/workspaces/test/common/workspaces.test.ts +++ b/src/vs/platform/workspaces/test/common/workspaces.test.ts @@ -5,6 +5,7 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { ISerializedSingleFolderWorkspaceIdentifier, ISerializedWorkspaceIdentifier, reviveIdentifier, hasWorkspaceFileExtension, isWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IEmptyWorkspaceIdentifier, toWorkspaceIdentifier, isEmptyWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'; suite('Workspaces', () => { @@ -46,4 +47,6 @@ suite('Workspaces', () => { assert.ok(!isSingleFolderWorkspaceIdentifier(identifier)); assert.ok(isWorkspaceIdentifier(identifier)); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/platform/workspaces/test/electron-main/workspaces.test.ts b/src/vs/platform/workspaces/test/electron-main/workspaces.test.ts index 42427b5ea6d..56e4d92fdc9 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspaces.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspaces.test.ts @@ -10,6 +10,7 @@ import * as path from 'vs/base/common/path'; import { isWindows } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { flakySuite, getRandomTestPath } from 'vs/base/test/node/testUtils'; import { getSingleFolderWorkspaceIdentifier, getWorkspaceIdentifier } from 'vs/platform/workspaces/node/workspaces'; @@ -64,4 +65,6 @@ flakySuite('Workspaces', () => { // single folder identifier (remote) assert.strictEqual(getSingleFolderWorkspaceIdentifier(URI.parse('vscode-remote:/hello/test'))?.id, '786de4f224d57691f218dc7f31ee2ee3'); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts b/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts index cefca23c785..c6bea307e34 100644 --- a/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts +++ b/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts @@ -168,7 +168,7 @@ export class MainThreadFileSystemEventService implements MainThreadFileSystemEve label: localize('cancel', "Skip Changes"), run: () => Choice.Cancel }, - checkbox: { label: localize('again', "Don't ask again") } + checkbox: { label: localize('again', "Do not ask me again") } }); if (result === Choice.Cancel) { // no changes wanted, don't persist cancel option diff --git a/src/vs/workbench/api/test/browser/extHost.api.impl.test.ts b/src/vs/workbench/api/test/browser/extHost.api.impl.test.ts index 2709cfda696..35e7ff35360 100644 --- a/src/vs/workbench/api/test/browser/extHost.api.impl.test.ts +++ b/src/vs/workbench/api/test/browser/extHost.api.impl.test.ts @@ -7,6 +7,7 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; import { originalFSPath } from 'vs/base/common/resources'; import { isWindows } from 'vs/base/common/platform'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; suite('ExtHost API', function () { test('issue #51387: originalFSPath', function () { @@ -18,4 +19,6 @@ suite('ExtHost API', function () { assert.strictEqual(originalFSPath(URI.revive(JSON.parse(JSON.stringify(URI.file('c:\\test'))))).charAt(0), 'c'); } }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts b/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts index 35e7543d864..3a60e4c025b 100644 --- a/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts +++ b/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts @@ -681,6 +681,33 @@ suite('ExtHostLanguageFeatureCommands', function () { }); }); + // --- document highlights + + test('"vscode.executeDocumentHighlights" API has stopped returning DocumentHighlight[]#200056', async function () { + + + disposables.push(extHost.registerDocumentHighlightProvider(nullExtensionDescription, defaultSelector, { + provideDocumentHighlights() { + return [ + new types.DocumentHighlight(new types.Range(0, 17, 0, 25), types.DocumentHighlightKind.Read) + ]; + } + })); + + await rpcProtocol.sync(); + + return commands.executeCommand('vscode.executeDocumentHighlights', model.uri, new types.Position(0, 0)).then(values => { + assert.ok(Array.isArray(values)); + assert.strictEqual(values.length, 1); + const [first] = values; + assert.strictEqual(first.range.start.line, 0); + assert.strictEqual(first.range.start.character, 17); + assert.strictEqual(first.range.end.line, 0); + assert.strictEqual(first.range.end.character, 25); + }); + + }); + // --- outline test('Outline, back and forth', function () { diff --git a/src/vs/workbench/api/test/browser/extHostDocumentData.test.ts b/src/vs/workbench/api/test/browser/extHostDocumentData.test.ts index b8912834f80..3f60f5ef898 100644 --- a/src/vs/workbench/api/test/browser/extHostDocumentData.test.ts +++ b/src/vs/workbench/api/test/browser/extHostDocumentData.test.ts @@ -441,6 +441,8 @@ suite('ExtHostDocumentData updates line mapping', () => { testLineMappingDirectionAfterEvents(lines, '\r\n', AssertDocumentLineMappingDirection.OffsetToPosition, e); } + ensureNoDisposablesAreLeakedInTestSuite(); + test('line mapping', () => { testLineMappingAfterEvents([ 'This is line one', diff --git a/src/vs/workbench/api/test/browser/extHostMessagerService.test.ts b/src/vs/workbench/api/test/browser/extHostMessagerService.test.ts index c65fe797901..a5c89dd257f 100644 --- a/src/vs/workbench/api/test/browser/extHostMessagerService.test.ts +++ b/src/vs/workbench/api/test/browser/extHostMessagerService.test.ts @@ -12,6 +12,7 @@ import { mock } from 'vs/base/test/common/mock'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; const emptyCommandService: ICommandService = { _serviceBrand: undefined, @@ -132,4 +133,6 @@ suite('ExtHostMessageService', function () { assert.strictEqual(handle, 42); }); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css index abba016e91d..99df125f3a8 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css @@ -234,7 +234,7 @@ /* Right aligned */ -.monaco-workbench .activitybar.right>.content :not(.monaco-menu)>.monaco-action-bar .profile-badge, +.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .profile-badge, .monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .badge { left: auto; right: 0; diff --git a/src/vs/workbench/browser/parts/editor/auxiliaryEditorPart.ts b/src/vs/workbench/browser/parts/editor/auxiliaryEditorPart.ts index f803e7dfd68..72b84741e46 100644 --- a/src/vs/workbench/browser/parts/editor/auxiliaryEditorPart.ts +++ b/src/vs/workbench/browser/parts/editor/auxiliaryEditorPart.ts @@ -19,7 +19,7 @@ import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; import { IAuxiliaryTitlebarPart } from 'vs/workbench/browser/parts/titlebar/titlebarPart'; import { WindowTitle } from 'vs/workbench/browser/parts/titlebar/windowTitle'; import { IAuxiliaryWindowOpenOptions, IAuxiliaryWindowService } from 'vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService'; -import { GroupsOrder, IAuxiliaryEditorPart } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { GroupDirection, GroupsOrder, IAuxiliaryEditorPart } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; @@ -220,10 +220,32 @@ class AuxiliaryEditorPartImpl extends EditorPart implements IAuxiliaryEditorPart } private doClose(mergeGroupsToMainPart: boolean): void { - if (mergeGroupsToMainPart && this.groups.some(group => group.count > 0)) { - this.mergeAllGroups(this.editorPartsView.mainPart.activeGroup); + if (mergeGroupsToMainPart) { + this.mergeGroupsToMainPart(); } this._onWillClose.fire(); } + + private mergeGroupsToMainPart(): void { + if (!this.groups.some(group => group.count > 0)) { + return; // skip if we have no editors opened + } + + // Find the most recent group that is not locked + let targetGroup: IEditorGroupView | undefined = undefined; + for (const group of this.editorPartsView.mainPart.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE)) { + if (!group.isLocked) { + targetGroup = group; + break; + } + } + + if (!targetGroup) { + targetGroup = this.editorPartsView.mainPart.addGroup(this.editorPartsView.mainPart.activeGroup, this.partOptions.openSideBySideDirection === 'right' ? GroupDirection.RIGHT : GroupDirection.DOWN); + } + + this.mergeAllGroups(targetGroup); + targetGroup.focus(); + } } diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 3281151bed1..8cf0c73d078 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -1900,11 +1900,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } private canLock(): boolean { - if (this.groupsView.isAuxiliary) { - return true; // always allow locking in auxiliary parts, even single groups - } - - return this.groupsView.groups.length > 1; // only allow locking if more than 1 group is opened + return this.editorPartsView.groups.length > 1; // only allow locking if more than 1 group is opened } //#endregion diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index e87d98624fc..55cc970ef96 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -13,7 +13,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IView, orthogonal, LayoutPriority, IViewSize, Direction, SerializableGrid, Sizing, ISerializedGrid, ISerializedNode, Orientation, GridBranchNode, isGridBranchNode, GridNode, createSerializedGrid, Grid } from 'vs/base/browser/ui/grid/grid'; import { GroupIdentifier, EditorInputWithOptions, IEditorPartOptions, IEditorPartOptionsChangeEvent, GroupModelChangeKind } from 'vs/workbench/common/editor'; import { EDITOR_GROUP_BORDER, EDITOR_PANE_BACKGROUND } from 'vs/workbench/common/theme'; -import { distinct, coalesce, firstOrDefault } from 'vs/base/common/arrays'; +import { distinct, coalesce } from 'vs/base/common/arrays'; import { IEditorGroupView, getEditorPartOptions, impactsEditorPartOptions, IEditorPartCreationOptions, IEditorPartsView, IEditorGroupsView } from 'vs/workbench/browser/parts/editor/editor'; import { EditorGroupView } from 'vs/workbench/browser/parts/editor/editorGroupView'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; @@ -811,12 +811,6 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { // Update container this.updateContainer(); - // Update locked state: clear when we are at just 1 group - // in case we are in the main editor part - if (this.count === 1 && !this.isAuxiliary) { - firstOrDefault(this.groups)?.lock(false); - } - // Event this._onDidRemoveGroup.fire(groupView); } diff --git a/src/vs/workbench/browser/parts/editor/editorParts.ts b/src/vs/workbench/browser/parts/editor/editorParts.ts index 155d6d153d2..deb9c9aedfa 100644 --- a/src/vs/workbench/browser/parts/editor/editorParts.ts +++ b/src/vs/workbench/browser/parts/editor/editorParts.ts @@ -13,7 +13,7 @@ import { IEditorGroupView, IEditorPartsView } from 'vs/workbench/browser/parts/e import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IAuxiliaryWindowOpenOptions } from 'vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService'; -import { distinct } from 'vs/base/common/arrays'; +import { distinct, firstOrDefault } from 'vs/base/common/arrays'; import { AuxiliaryEditorPart } from 'vs/workbench/browser/parts/editor/auxiliaryEditorPart'; import { MultiWindowParts } from 'vs/workbench/browser/part'; @@ -94,7 +94,7 @@ export class EditorParts extends MultiWindowParts implements IEditor disposables.add(part.onDidChangeActiveGroup(group => this._onDidActiveGroupChange.fire(group))); disposables.add(part.onDidAddGroup(group => this._onDidAddGroup.fire(group))); - disposables.add(part.onDidRemoveGroup(group => this._onDidRemoveGroup.fire(group))); + disposables.add(part.onDidRemoveGroup(group => this.handleOnDidRemoveGroup(group))); disposables.add(part.onDidMoveGroup(group => this._onDidMoveGroup.fire(group))); disposables.add(part.onDidActivateGroup(group => this._onDidActivateGroup.fire(group))); disposables.add(part.onDidChangeGroupMaximized(maximized => this._onDidChangeGroupMaximized.fire(maximized))); @@ -103,6 +103,17 @@ export class EditorParts extends MultiWindowParts implements IEditor disposables.add(part.onDidChangeGroupLocked(group => this._onDidChangeGroupLocked.fire(group))); } + private handleOnDidRemoveGroup(group: IEditorGroupView): void { + + // Reset locked state when only one group is remaining + if (this.count === 1) { + firstOrDefault(this.mainPart.groups)?.lock(false); + } + + // Events + this._onDidRemoveGroup.fire(group); + } + private doUpdateMostRecentActive(part: EditorPart, makeMostRecentlyActive?: boolean): void { const index = this.mostRecentActiveParts.indexOf(part); diff --git a/src/vs/workbench/browser/parts/editor/media/breadcrumbscontrol.css b/src/vs/workbench/browser/parts/editor/media/breadcrumbscontrol.css index 3b8bac4565d..ec3ef9c9c13 100644 --- a/src/vs/workbench/browser/parts/editor/media/breadcrumbscontrol.css +++ b/src/vs/workbench/browser/parts/editor/media/breadcrumbscontrol.css @@ -3,17 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-workbench .part.editor>.content .editor-group-container .breadcrumbs-control.hidden { +.monaco-workbench .part.editor > .content .editor-group-container .breadcrumbs-control.hidden { display: none; } -.monaco-workbench .part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.selected .monaco-icon-label, -.monaco-workbench .part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.focused .monaco-icon-label { +.monaco-workbench .part.editor > .content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.selected .monaco-icon-label, +.monaco-workbench .part.editor > .content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.focused .monaco-icon-label { text-decoration-line: underline; } -.monaco-workbench .part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.selected .hint-more, -.monaco-workbench .part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.focused .hint-more { +.monaco-workbench .part.editor > .content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.selected .hint-more, +.monaco-workbench .part.editor > .content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.focused .hint-more { text-decoration-line: underline; } @@ -41,22 +41,22 @@ flex-direction: column; } -.monaco-workbench .monaco-breadcrumbs-picker .highlighting-tree>.input { +.monaco-workbench .monaco-breadcrumbs-picker .highlighting-tree > .input { padding: 5px 9px; position: relative; box-sizing: border-box; height: 36px; } -.monaco-workbench .monaco-breadcrumbs-picker .highlighting-tree>.tree { +.monaco-workbench .monaco-breadcrumbs-picker .highlighting-tree > .tree { height: calc(100% - 36px); } -.monaco-workbench .monaco-breadcrumbs-picker .highlighting-tree.inactive>.input { +.monaco-workbench .monaco-breadcrumbs-picker .highlighting-tree.inactive > .input { display: none; } -.monaco-workbench .monaco-breadcrumbs-picker .highlighting-tree.inactive>.tree { +.monaco-workbench .monaco-breadcrumbs-picker .highlighting-tree.inactive > .tree { height: 100%; } diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 2c0acaa442a..ee6a8e501c8 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -928,7 +928,7 @@ export interface IFileEditorInput extends EditorInput, IEncodingSupport, ILangua isResolved(): boolean; } -export interface IFileEditorInputOptions extends ITextEditorOptions { +export interface IFileLimitedEditorInputOptions extends IEditorOptions { /** * If provided, the size of the file will be checked against the limits @@ -937,6 +937,8 @@ export interface IFileEditorInputOptions extends ITextEditorOptions { readonly limits?: IFileReadLimits; } +export interface IFileEditorInputOptions extends ITextEditorOptions, IFileLimitedEditorInputOptions { } + export function createTooLargeFileError(group: IEditorGroup, input: EditorInput, options: IEditorOptions | undefined, message: string, preferencesService: IPreferencesService): Error { return createEditorOpenError(message, [ toAction({ diff --git a/src/vs/workbench/common/editor/resourceEditorInput.ts b/src/vs/workbench/common/editor/resourceEditorInput.ts index d1d5f8c5674..6f5af0deee3 100644 --- a/src/vs/workbench/common/editor/resourceEditorInput.ts +++ b/src/vs/workbench/common/editor/resourceEditorInput.ts @@ -3,14 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Verbosity, EditorInputWithPreferredResource, EditorInputCapabilities } from 'vs/workbench/common/editor'; +import { Verbosity, EditorInputWithPreferredResource, EditorInputCapabilities, IFileLimitedEditorInputOptions } from 'vs/workbench/common/editor'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { URI } from 'vs/base/common/uri'; -import { IFileService } from 'vs/platform/files/common/files'; +import { ByteSize, IFileReadLimits, IFileService, getLargeFileConfirmationLimit } from 'vs/platform/files/common/files'; import { ILabelService } from 'vs/platform/label/common/label'; import { dirname, isEqual } from 'vs/base/common/resources'; import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { IMarkdownString } from 'vs/base/common/htmlContent'; +import { isConfigured } from 'vs/platform/configuration/common/configuration'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration'; /** * The base class for all editor inputs that open resources. @@ -43,7 +45,8 @@ export abstract class AbstractResourceEditorInput extends EditorInput implements preferredResource: URI | undefined, @ILabelService protected readonly labelService: ILabelService, @IFileService protected readonly fileService: IFileService, - @IFilesConfigurationService protected readonly filesConfigurationService: IFilesConfigurationService + @IFilesConfigurationService protected readonly filesConfigurationService: IFilesConfigurationService, + @ITextResourceConfigurationService protected readonly textResourceConfigurationService: ITextResourceConfigurationService ) { super(); @@ -179,4 +182,27 @@ export abstract class AbstractResourceEditorInput extends EditorInput implements override isReadonly(): boolean | IMarkdownString { return this.filesConfigurationService.isReadonly(this.resource); } + + protected ensureLimits(options?: IFileLimitedEditorInputOptions): IFileReadLimits | undefined { + if (options?.limits) { + return options.limits; // respect passed in limits if any + } + + // We want to determine the large file configuration based on the best defaults + // for the resource but also respecting user settings. We only apply user settings + // if explicitly configured by the user. Otherwise we pick the best limit for the + // resource scheme. + + const defaultSizeLimit = getLargeFileConfirmationLimit(this.resource); + let configuredSizeLimit: number | undefined = undefined; + + const configuredSizeLimitMb = this.textResourceConfigurationService.inspect(this.resource, null, 'workbench.editorLargeFileConfirmation'); + if (isConfigured(configuredSizeLimitMb)) { + configuredSizeLimit = configuredSizeLimitMb.value * ByteSize.MB; // normalize to MB + } + + return { + size: configuredSizeLimit ?? defaultSizeLimit + }; + } } diff --git a/src/vs/workbench/common/editor/textResourceEditorInput.ts b/src/vs/workbench/common/editor/textResourceEditorInput.ts index 02217560ffd..8416d2cc249 100644 --- a/src/vs/workbench/common/editor/textResourceEditorInput.ts +++ b/src/vs/workbench/common/editor/textResourceEditorInput.ts @@ -18,6 +18,7 @@ import { TextResourceEditorModel } from 'vs/workbench/common/editor/textResource import { IReference } from 'vs/base/common/lifecycle'; import { createTextBufferFactory } from 'vs/editor/common/model/textModel'; import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration'; /** * The base class for all editor inputs that open in text editors. @@ -31,9 +32,10 @@ export abstract class AbstractTextResourceEditorInput extends AbstractResourceEd @ITextFileService protected readonly textFileService: ITextFileService, @ILabelService labelService: ILabelService, @IFileService fileService: IFileService, - @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService ) { - super(resource, preferredResource, labelService, fileService, filesConfigurationService); + super(resource, preferredResource, labelService, fileService, filesConfigurationService, textResourceConfigurationService); } override save(group: GroupIdentifier, options?: ITextFileSaveOptions): Promise { @@ -104,9 +106,10 @@ export class TextResourceEditorInput extends AbstractTextResourceEditorInput imp @IEditorService editorService: IEditorService, @IFileService fileService: IFileService, @ILabelService labelService: ILabelService, - @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService ) { - super(resource, undefined, editorService, textFileService, labelService, fileService, filesConfigurationService); + super(resource, undefined, editorService, textFileService, labelService, fileService, filesConfigurationService, textResourceConfigurationService); } override getName(): string { diff --git a/src/vs/workbench/contrib/chat/test/common/chatModel.test.ts b/src/vs/workbench/contrib/chat/test/common/chatModel.test.ts index 33f0e1d0a06..60197332945 100644 --- a/src/vs/workbench/contrib/chat/test/common/chatModel.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/chatModel.test.ts @@ -122,6 +122,8 @@ suite('ChatModel', () => { }); suite('Response', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + test('content, markdown', async () => { const response = new Response([]); response.updateContent({ content: 'text', kind: 'content' }); diff --git a/src/vs/workbench/contrib/comments/browser/media/review.css b/src/vs/workbench/contrib/comments/browser/media/review.css index b2ce28c5e14..cad293ca09e 100644 --- a/src/vs/workbench/contrib/comments/browser/media/review.css +++ b/src/vs/workbench/contrib/comments/browser/media/review.css @@ -298,8 +298,8 @@ width: auto; } -.review-widget .body .comment-additional-actions .button-bar>.monaco-text-button, -.review-widget .body .comment-additional-actions .button-bar>.monaco-button-dropdown { +.review-widget .body .comment-additional-actions .button-bar > .monaco-text-button, +.review-widget .body .comment-additional-actions .button-bar > .monaco-button-dropdown { margin: 0 10px 0 0; } diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index a0e2bd56df4..9f1dad419b3 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -493,7 +493,7 @@ export class DebugService implements IDebugService { return false; } - const cfg = await this.configurationManager.resolveDebugConfigurationWithSubstitutedVariables(launch && launch.workspace ? launch.workspace.uri : undefined, type, resolvedConfig, initCancellationToken.token); + const cfg = await this.configurationManager.resolveDebugConfigurationWithSubstitutedVariables(launch && launch.workspace ? launch.workspace.uri : undefined, resolvedConfig.type, resolvedConfig, initCancellationToken.token); if (!cfg) { if (launch && type && cfg === null && !initCancellationToken.token.isCancellationRequested) { // show launch.json only for "config" being "null". await launch.openConfigFile({ preserveFocus: true, type }, initCancellationToken.token); diff --git a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts index b9327dbdced..88e597e76be 100644 --- a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts +++ b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts @@ -281,7 +281,7 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution { private get yRange(): [number, number] { if (!this._yRange) { const isTitleBarVisible = this.layoutService.isVisible(Parts.TITLEBAR_PART, dom.getWindow(this.layoutService.activeContainer)); - const yMin = isTitleBarVisible ? 0 : this.layoutService.mainContainerOffset.top; + const yMin = isTitleBarVisible ? this.layoutService.mainContainerOffset.top : 0; let yMax = 0; if (isTitleBarVisible) { diff --git a/src/vs/workbench/contrib/debug/browser/disassemblyView.ts b/src/vs/workbench/contrib/debug/browser/disassemblyView.ts index cfef6373c3e..618aa8994d8 100644 --- a/src/vs/workbench/contrib/debug/browser/disassemblyView.ts +++ b/src/vs/workbench/contrib/debug/browser/disassemblyView.ts @@ -339,7 +339,7 @@ export class DisassemblyView extends EditorPane { async goToInstructionAndOffset(instructionReference: string, offset: number, focus?: boolean) { let addr = this._referenceToMemoryAddress.get(instructionReference); if (addr === undefined) { - await this.loadDisassembledInstructions(instructionReference, 0, -DisassemblyView.NUM_INSTRUCTIONS_TO_LOAD, DisassemblyView.NUM_INSTRUCTIONS_TO_LOAD); + await this.loadDisassembledInstructions(instructionReference, 0, -DisassemblyView.NUM_INSTRUCTIONS_TO_LOAD, DisassemblyView.NUM_INSTRUCTIONS_TO_LOAD * 2); addr = this._referenceToMemoryAddress.get(instructionReference); } diff --git a/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css b/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css index 4ae58e118a1..b2eaa27034a 100644 --- a/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css +++ b/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css @@ -10,12 +10,12 @@ text-overflow: ellipsis; } -.monaco-action-bar .action-item>.action-label.extension-action.label, -.monaco-action-bar .action-dropdown-item>.action-label.extension-action.label { +.monaco-action-bar .action-item > .action-label.extension-action.label, +.monaco-action-bar .action-dropdown-item > .action-label.extension-action.label { padding: 0 5px; } -.monaco-action-bar .action-dropdown-item>.monaco-dropdown .action-label { +.monaco-action-bar .action-dropdown-item > .monaco-dropdown .action-label { padding: 0; } @@ -36,7 +36,7 @@ } .monaco-action-bar .action-item .action-label.extension-action.label, -.monaco-action-bar .action-item.action-dropdown-item>.action-dropdown-item-separator { +.monaco-action-bar .action-item.action-dropdown-item > .action-dropdown-item-separator { background-color: var(--vscode-extensionButton-background) !important; } @@ -48,12 +48,12 @@ background-color: var(--vscode-extensionButton-hoverBackground) !important; } -.monaco-action-bar .action-item.action-dropdown-item>.action-dropdown-item-separator>div { +.monaco-action-bar .action-item.action-dropdown-item > .action-dropdown-item-separator > div { background-color: var(--vscode-extensionButton-separator); } .monaco-action-bar .action-item .action-label.extension-action.label.prominent, -.monaco-action-bar .action-item.action-dropdown-item>.action-dropdown-item-separator.prominent { +.monaco-action-bar .action-item.action-dropdown-item > .action-dropdown-item-separator.prominent { background-color: var(--vscode-extensionButton-prominentBackground); } @@ -69,7 +69,7 @@ border: 1px solid var(--vscode-contrastBorder); } -.monaco-action-bar .action-item.action-dropdown-item>.action-dropdown-item-separator { +.monaco-action-bar .action-item.action-dropdown-item > .action-dropdown-item-separator { border-top: 1px solid var(--vscode-contrastBorder); border-bottom: 1px solid var(--vscode-contrastBorder); } diff --git a/src/vs/workbench/contrib/extensions/browser/media/runtimeExtensionsEditor.css b/src/vs/workbench/contrib/extensions/browser/media/runtimeExtensionsEditor.css index e1c4ea5afd2..7187efb1757 100644 --- a/src/vs/workbench/contrib/extensions/browser/media/runtimeExtensionsEditor.css +++ b/src/vs/workbench/contrib/extensions/browser/media/runtimeExtensionsEditor.css @@ -31,7 +31,7 @@ text-align: right; } -.runtime-extensions-editor .extension .desc>.msg>span:not(:last-child)::after { +.runtime-extensions-editor .extension .desc > .msg > span:not(:last-child)::after { content: '\2022'; padding: 0 4px; opacity: .8; diff --git a/src/vs/workbench/contrib/files/browser/editors/fileEditorInput.ts b/src/vs/workbench/contrib/files/browser/editors/fileEditorInput.ts index 3f4b1910cf4..dd25f4509bc 100644 --- a/src/vs/workbench/contrib/files/browser/editors/fileEditorInput.ts +++ b/src/vs/workbench/contrib/files/browser/editors/fileEditorInput.ts @@ -9,7 +9,7 @@ import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { AbstractTextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput'; import { ITextResourceEditorInput } from 'vs/platform/editor/common/editor'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; -import { ByteSize, IFileReadLimits, IFileService, getLargeFileConfirmationLimit } from 'vs/platform/files/common/files'; +import { IFileService } from 'vs/platform/files/common/files'; import { ITextFileService, TextFileEditorModelState, TextFileResolveReason, TextFileOperationError, TextFileOperationResult, ITextFileEditorModel, EncodingMode } from 'vs/workbench/services/textfile/common/textfiles'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IReference, dispose, DisposableStore } from 'vs/base/common/lifecycle'; @@ -24,7 +24,6 @@ import { Schemas } from 'vs/base/common/network'; import { createTextBufferFactory } from 'vs/editor/common/model/textModel'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration'; -import { isConfigured } from 'vs/platform/configuration/common/configuration'; import { IMarkdownString } from 'vs/base/common/htmlContent'; const enum ForceOpenAs { @@ -99,9 +98,9 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService, @IEditorService editorService: IEditorService, @IPathService private readonly pathService: IPathService, - @ITextResourceConfigurationService private readonly textResourceConfigurationService: ITextResourceConfigurationService + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService ) { - super(resource, preferredResource, editorService, textFileService, labelService, fileService, filesConfigurationService); + super(resource, preferredResource, editorService, textFileService, labelService, fileService, filesConfigurationService, textResourceConfigurationService); this.model = this.textFileService.files.get(resource); @@ -396,29 +395,6 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements } } - private ensureLimits(options?: IFileEditorInputOptions): IFileReadLimits | undefined { - if (options?.limits) { - return options.limits; // respect passed in limits if any - } - - // We want to determine the large file configuration based on the best defaults - // for the resource but also respecting user settings. We only apply user settings - // if explicitly configured by the user. Otherwise we pick the best limit for the - // resource scheme. - - const defaultSizeLimit = getLargeFileConfirmationLimit(this.resource); - let configuredSizeLimit: number | undefined = undefined; - - const configuredSizeLimitMb = this.textResourceConfigurationService.inspect(this.resource, null, 'workbench.editorLargeFileConfirmation'); - if (isConfigured(configuredSizeLimitMb)) { - configuredSizeLimit = configuredSizeLimitMb.value * ByteSize.MB; // normalize to MB - } - - return { - size: configuredSizeLimit ?? defaultSizeLimit - }; - } - private async doResolveAsBinary(): Promise { const model = this.instantiationService.createInstance(BinaryEditorModel, this.preferredResource, this.getName()); await model.resolve(); diff --git a/src/vs/workbench/contrib/files/test/browser/explorerModel.test.ts b/src/vs/workbench/contrib/files/test/browser/explorerModel.test.ts index 9aa3627dbaa..938fed848a2 100644 --- a/src/vs/workbench/contrib/files/test/browser/explorerModel.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/explorerModel.test.ts @@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri'; import { join } from 'vs/base/common/path'; import { validateFileName } from 'vs/workbench/contrib/files/browser/fileActions'; import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; -import { toResource } from 'vs/base/test/common/utils'; +import { ensureNoDisposablesAreLeakedInTestSuite, toResource } from 'vs/base/test/common/utils'; import { TestFileService, TestPathService } from 'vs/workbench/test/browser/workbenchTestServices'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { NullFilesConfigurationService } from 'vs/workbench/test/common/workbenchTestServices'; @@ -277,4 +277,6 @@ suite('Files - View Model', function () { ExplorerItem.mergeLocalWithDisk(merge2, merge1); assert.ok(existingChild === merge1.getChild(existingChild!.name)); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/workbench/contrib/files/test/browser/fileActions.test.ts b/src/vs/workbench/contrib/files/test/browser/fileActions.test.ts index bfa18a3b7a4..e1e8db24108 100644 --- a/src/vs/workbench/contrib/files/test/browser/fileActions.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/fileActions.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { incrementFileName } from 'vs/workbench/contrib/files/browser/fileActions'; suite('Files - Increment file name simple', () => { @@ -134,6 +135,7 @@ suite('Files - Increment file name simple', () => { assert.strictEqual(result, 'test copy 2'); }); + ensureNoDisposablesAreLeakedInTestSuite(); }); suite('Files - Increment file name smart', () => { @@ -324,4 +326,5 @@ suite('Files - Increment file name smart', () => { assert.strictEqual(result, '2-test'); }); + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css index 6d16be3ce3a..9e4e77cfe38 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css @@ -93,7 +93,7 @@ } /* UGLY - fighting against workbench styles */ -.monaco-workbench .part.editor>.content .monaco-editor .inline-chat .progress .monaco-progress-container { +.monaco-workbench .part.editor > .content .monaco-editor .inline-chat .progress .monaco-progress-container { top: 0; } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts index e352642e2d6..90d658b07d0 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts @@ -900,6 +900,10 @@ export class LiveStrategy3 extends EditModeStrategy { } : undefined; + this._sessionStore.add(this._session.textModelN.onDidChangeContent(e => { + this._showDiff(true, true); + })); + const zoneLineNumber = this._zone.position!.lineNumber; const myDistance = zoneLineNumber <= modifiedRange.startLineNumber ? modifiedRange.startLineNumber - zoneLineNumber diff --git a/src/vs/workbench/contrib/languageStatus/browser/media/languageStatus.css b/src/vs/workbench/contrib/languageStatus/browser/media/languageStatus.css index da152cb9208..f7fb23f59c6 100644 --- a/src/vs/workbench/contrib/languageStatus/browser/media/languageStatus.css +++ b/src/vs/workbench/contrib/languageStatus/browser/media/languageStatus.css @@ -25,7 +25,7 @@ } } -.monaco-workbench .statusbar DIV#status\.languageStatus A>SPAN.codicon.wiggle { +.monaco-workbench .statusbar DIV#status\.languageStatus A > SPAN.codicon.wiggle { animation-duration: .8s; animation-iteration-count: 1; animation-name: wiggle; @@ -62,60 +62,60 @@ border-bottom: 1px solid var(--vscode-notifications-border); } -.monaco-workbench .hover-language-status>.severity { +.monaco-workbench .hover-language-status > .severity { padding-right: 8px; flex: 1; margin: auto; display: none; } -.monaco-workbench .hover-language-status>.severity.sev3 { +.monaco-workbench .hover-language-status > .severity.sev3 { color: var(--vscode-notificationsErrorIcon-foreground) } -.monaco-workbench .hover-language-status>.severity.sev2 { +.monaco-workbench .hover-language-status > .severity.sev2 { color: var(--vscode-notificationsInfoIcon-foreground) } -.monaco-workbench .hover-language-status>.severity.show { +.monaco-workbench .hover-language-status > .severity.show { display: inherit; } -.monaco-workbench .hover-language-status>.element { +.monaco-workbench .hover-language-status > .element { display: flex; justify-content: space-between; vertical-align: middle; flex-grow: 100; } -.monaco-workbench .hover-language-status>.element>.left>.detail:not(:empty)::before { +.monaco-workbench .hover-language-status > .element > .left > .detail:not(:empty)::before { content: '\2013'; padding: 0 4px; opacity: 0.6; } -.monaco-workbench .hover-language-status>.element>.left>.label:empty { +.monaco-workbench .hover-language-status > .element > .left > .label:empty { display: none; } -.monaco-workbench .hover-language-status>.element .left { +.monaco-workbench .hover-language-status > .element .left { margin: auto 0; } -.monaco-workbench .hover-language-status>.element .right { +.monaco-workbench .hover-language-status > .element .right { margin: auto 0; display: flex; } -.monaco-workbench .hover-language-status>.element .right:not(:empty) { +.monaco-workbench .hover-language-status > .element .right:not(:empty) { padding-left: 16px; } -.monaco-workbench .hover-language-status>.element .right .monaco-link { +.monaco-workbench .hover-language-status > .element .right .monaco-link { margin: auto 0; white-space: nowrap; } -.monaco-workbench .hover-language-status>.element .right .monaco-action-bar:not(:first-child) { +.monaco-workbench .hover-language-status > .element .right .monaco-action-bar:not(:first-child) { padding-left: 8px; } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts index e9f69bfa0ad..3304f0b90b7 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts @@ -8,6 +8,7 @@ import { autorun } from 'vs/base/common/observable'; import { isEqual } from 'vs/base/common/resources'; import { isDefined } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration'; import { localize } from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IFileService } from 'vs/platform/files/common/files'; @@ -60,9 +61,10 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements @ILabelService labelService: ILabelService, @IFileService fileService: IFileService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService ) { - super(result, undefined, editorService, textFileService, labelService, fileService, filesConfigurationService); + super(result, undefined, editorService, textFileService, labelService, fileService, filesConfigurationService, textResourceConfigurationService); } override dispose(): void { diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts index 9b3f245a2dd..b043f0840a1 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts @@ -473,7 +473,7 @@ class WorkspaceMergeEditorInputModel extends EditorModel implements IMergeEditor primaryButton: someUnhandledConflicts ? localize({ key: 'workspace.closeWithConflicts', comment: ['&& denotes a mnemonic'] }, '&&Close with Conflicts') : localize({ key: 'workspace.close', comment: ['&& denotes a mnemonic'] }, '&&Close'), - checkbox: { label: localize('noMoreWarn', "Don't ask again") } + checkbox: { label: localize('noMoreWarn', "Do not ask me again") } }); if (checkboxChecked) { diff --git a/src/vs/workbench/contrib/notebook/browser/media/notebook.css b/src/vs/workbench/contrib/notebook/browser/media/notebook.css index c22bc652ca7..309b3b4ef84 100644 --- a/src/vs/workbench/contrib/notebook/browser/media/notebook.css +++ b/src/vs/workbench/contrib/notebook/browser/media/notebook.css @@ -258,7 +258,7 @@ text-align: center; } -.monaco-workbench .notebookOverlay>.cell-list-container>.monaco-list>.monaco-scrollable-element>.monaco-list-rows>.monaco-list-row .cell-statusbar-hidden .execution-count-label { +.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-statusbar-hidden .execution-count-label { line-height: 15px; } diff --git a/src/vs/workbench/contrib/notebook/browser/media/notebookCellChat.css b/src/vs/workbench/contrib/notebook/browser/media/notebookCellChat.css index 5c0081e507d..fda2877f566 100644 --- a/src/vs/workbench/contrib/notebook/browser/media/notebookCellChat.css +++ b/src/vs/workbench/contrib/notebook/browser/media/notebookCellChat.css @@ -97,7 +97,7 @@ } /* UGLY - fighting against workbench styles */ -.monaco-workbench .part.editor>.content .monaco-editor .inline-chat .progress .monaco-progress-container { +.monaco-workbench .part.editor > .content .monaco-editor .inline-chat .progress .monaco-progress-container { top: 0; } diff --git a/src/vs/workbench/contrib/notebook/browser/media/notebookFolding.css b/src/vs/workbench/contrib/notebook/browser/media/notebookFolding.css index 8dc8d7eb123..7433c9a7eb2 100644 --- a/src/vs/workbench/contrib/notebook/browser/media/notebookFolding.css +++ b/src/vs/workbench/contrib/notebook/browser/media/notebookFolding.css @@ -43,7 +43,7 @@ padding: 4px 4px 4px 4px; } -.monaco-workbench .notebookOverlay>.cell-list-container .notebook-folded-hint { +.monaco-workbench .notebookOverlay > .cell-list-container .notebook-folded-hint { position: absolute; user-select: none; } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts index 7bcd5a348d9..2370b8a2972 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts @@ -17,14 +17,14 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/tex import { localize } from 'vs/nls'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IEditorOptions } from 'vs/platform/editor/common/editor'; -import { IFileService } from 'vs/platform/files/common/files'; +import { ByteSize, FileOperationError, FileOperationResult, IFileService, TooLargeFileOperationError } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Selection } from 'vs/editor/common/core/selection'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; -import { DEFAULT_EDITOR_ASSOCIATION, EditorPaneSelectionChangeReason, EditorPaneSelectionCompareResult, EditorResourceAccessor, IEditorMemento, IEditorOpenContext, IEditorPaneSelection, IEditorPaneSelectionChangeEvent, createEditorOpenError, isEditorOpenError } from 'vs/workbench/common/editor'; +import { DEFAULT_EDITOR_ASSOCIATION, EditorPaneSelectionChangeReason, EditorPaneSelectionCompareResult, EditorResourceAccessor, IEditorMemento, IEditorOpenContext, IEditorPaneSelection, IEditorPaneSelectionChangeEvent, createEditorOpenError, createTooLargeFileError, isEditorOpenError } from 'vs/workbench/common/editor'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { SELECT_KERNEL_ID } from 'vs/workbench/contrib/notebook/browser/controller/coreActions'; import { INotebookEditorOptions, INotebookEditorPane, INotebookEditorViewState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; @@ -46,6 +46,7 @@ import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/com import { streamToBuffer } from 'vs/base/common/buffer'; import { ILogService } from 'vs/platform/log/common/log'; import { INotebookEditorWorkerService } from 'vs/workbench/contrib/notebook/common/services/notebookWorkerService'; +import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; const NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'NotebookEditorViewState'; @@ -90,6 +91,7 @@ export class NotebookEditor extends EditorPane implements INotebookEditorPane { @IWorkingCopyBackupService private readonly _workingCopyBackupService: IWorkingCopyBackupService, @ILogService private readonly logService: ILogService, @INotebookEditorWorkerService private readonly _notebookEditorWorkerService: INotebookEditorWorkerService, + @IPreferencesService private readonly _preferencesService: IPreferencesService, ) { super(NotebookEditor.ID, telemetryService, themeService, storageService); this._editorMemento = this.getEditorMemento(_editorGroupService, configurationService, NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY); @@ -327,6 +329,18 @@ export class NotebookEditor extends EditorPane implements INotebookEditorPane { throw e; } + // Handle case where a file is too large to open without confirmation + if ((e).fileOperationResult === FileOperationResult.FILE_TOO_LARGE && this.group) { + let message: string; + if (e instanceof TooLargeFileOperationError) { + message = localize('notebookTooLargeForHeapErrorWithSize', "The notebook is not displayed in the notebook editor because it is very large ({0}).", ByteSize.formatSize(e.size)); + } else { + message = localize('notebookTooLargeForHeapErrorWithoutSize', "The notebook is not displayed in the notebook editor because it is very large."); + } + + throw createTooLargeFileError(this.group, input, options, message, this._preferencesService); + } + const error = createEditorOpenError(e instanceof Error ? e : new Error((e ? e.message : '')), [ toAction({ id: 'workbench.notebook.action.openInTextEditor', label: localize('notebookOpenInTextEditor', "Open in Text Editor"), run: async () => { diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 99230c87970..e88290fa063 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -30,6 +30,7 @@ import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/no import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { IWorkingCopyBackupMeta, IWorkingCopySaveEvent } from 'vs/workbench/services/workingCopy/common/workingCopy'; import { IMarkdownString } from 'vs/base/common/htmlContent'; +import { IFileReadLimits } from 'vs/platform/files/common/files'; export const NOTEBOOK_EDITOR_ID = 'workbench.editor.notebook'; export const NOTEBOOK_DIFF_EDITOR_ID = 'workbench.editor.notebookTextDiffEditor'; @@ -787,6 +788,11 @@ export interface INotebookLoadOptions { * Go to disk bypassing any cache of the model if any. */ forceReadFromFile?: boolean; + /** + * If provided, the size of the file will be checked against the limits + * and an error will be thrown if any limit is exceeded. + */ + readonly limits?: IFileReadLimits; } export interface IResolvedNotebookEditorModel extends INotebookEditorModel { diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorInput.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorInput.ts index 1d6bba54100..8a0f53e0b8c 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorInput.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorInput.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as glob from 'vs/base/common/glob'; -import { GroupIdentifier, ISaveOptions, IMoveResult, IRevertOptions, EditorInputCapabilities, Verbosity, IUntypedEditorInput } from 'vs/workbench/common/editor'; +import { GroupIdentifier, ISaveOptions, IMoveResult, IRevertOptions, EditorInputCapabilities, Verbosity, IUntypedEditorInput, IFileLimitedEditorInputOptions } from 'vs/workbench/common/editor'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { INotebookService, SimpleNotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookService'; import { URI } from 'vs/base/common/uri'; @@ -18,7 +18,7 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { Schemas } from 'vs/base/common/network'; import { IFileService } from 'vs/platform/files/common/files'; import { AbstractResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; -import { IEditorOptions, IResourceEditorInput } from 'vs/platform/editor/common/editor'; +import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; import { onUnexpectedError } from 'vs/base/common/errors'; import { VSBuffer } from 'vs/base/common/buffer'; import { IWorkingCopyIdentifier } from 'vs/workbench/services/workingCopy/common/workingCopy'; @@ -29,6 +29,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { localize } from 'vs/nls'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IMarkdownString } from 'vs/base/common/htmlContent'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration'; export interface NotebookEditorInputOptions { startDirty?: boolean; @@ -79,9 +80,10 @@ export class NotebookEditorInput extends AbstractResourceEditorInput { @IFileService fileService: IFileService, @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService, @IExtensionService extensionService: IExtensionService, - @IEditorService editorService: IEditorService + @IEditorService editorService: IEditorService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService ) { - super(resource, preferredResource, labelService, fileService, filesConfigurationService); + super(resource, preferredResource, labelService, fileService, filesConfigurationService, textResourceConfigurationService); this._defaultDirtyState = !!options.startDirty; // Automatically resolve this input when the "wanted" model comes to life via @@ -281,7 +283,7 @@ export class NotebookEditorInput extends AbstractResourceEditorInput { } } - override async resolve(_options?: IEditorOptions, perf?: NotebookPerfMarks): Promise { + override async resolve(_options?: IFileLimitedEditorInputOptions, perf?: NotebookPerfMarks): Promise { if (!await this._notebookService.canResolve(this.viewType)) { return null; } @@ -293,7 +295,7 @@ export class NotebookEditorInput extends AbstractResourceEditorInput { this._sideLoadedListener.dispose(); if (!this._editorModelReference) { - const ref = await this._notebookModelResolverService.resolve(this.resource, this.viewType); + const ref = await this._notebookModelResolverService.resolve(this.resource, this.viewType, this.ensureLimits(_options)); if (this._editorModelReference) { // Re-entrant, double resolve happened. Dispose the addition references and proceed // with the truth. @@ -313,7 +315,7 @@ export class NotebookEditorInput extends AbstractResourceEditorInput { this._onDidChangeDirty.fire(); } } else { - this._editorModelReference.object.load(); + this._editorModelReference.object.load({ limits: this.ensureLimits(_options) }); } if (this.options._backupId) { diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts index cb01185b511..4e7864c0667 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts @@ -136,7 +136,10 @@ export class SimpleNotebookEditorModel extends EditorModel implements INotebookE } this._workingCopy.onDidRevert(() => this._onDidRevertUntitled.fire()); } else { - this._workingCopy = await this._workingCopyManager.resolve(this.resource, options?.forceReadFromFile ? { reload: { async: false, force: true } } : undefined); + this._workingCopy = await this._workingCopyManager.resolve(this.resource, { + limits: options?.limits, + reload: options?.forceReadFromFile ? { async: false, force: true } : undefined + }); this._workingCopyListeners.add(this._workingCopy.onDidSave(e => this._onDidSave.fire(e))); this._workingCopyListeners.add(this._workingCopy.onDidChangeOrphaned(() => this._onDidChangeOrphaned.fire())); this._workingCopyListeners.add(this._workingCopy.onDidChangeReadonly(() => this._onDidChangeReadonly.fire())); @@ -152,7 +155,8 @@ export class SimpleNotebookEditorModel extends EditorModel implements INotebookE reload: { async: !options?.forceReadFromFile, force: options?.forceReadFromFile - } + }, + limits: options?.limits }); } diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts index e2d2a6c4fe4..3eff1eb5060 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts @@ -8,6 +8,7 @@ import { URI } from 'vs/base/common/uri'; import { IResolvedNotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IReference } from 'vs/base/common/lifecycle'; import { Event, IWaitUntil } from 'vs/base/common/event'; +import { IFileReadLimits } from 'vs/platform/files/common/files'; export const INotebookEditorModelResolverService = createDecorator('INotebookModelResolverService'); @@ -49,6 +50,6 @@ export interface INotebookEditorModelResolverService { isDirty(resource: URI): boolean; - resolve(resource: URI, viewType?: string): Promise>; - resolve(resource: IUntitledNotebookResource, viewType: string): Promise>; + resolve(resource: URI, viewType?: string, limits?: IFileReadLimits): Promise>; + resolve(resource: IUntitledNotebookResource, viewType: string, limits?: IFileReadLimits): Promise>; } diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts index 9da04357e1b..bbc69d31aa2 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts @@ -21,6 +21,7 @@ import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/noteb import { assertIsDefined } from 'vs/base/common/types'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IFileReadLimits } from 'vs/platform/files/common/files'; class NotebookModelReferenceCollection extends ReferenceCollection> { @@ -58,7 +59,7 @@ class NotebookModelReferenceCollection extends ReferenceCollection { + protected async createReferencedObject(key: string, viewType: string, hasAssociatedFilePath: boolean, limits?: IFileReadLimits): Promise { // Untrack as being disposed this.modelsToDispose.delete(key); @@ -77,7 +78,7 @@ class NotebookModelReferenceCollection extends ReferenceCollection>; - async resolve(resource: IUntitledNotebookResource, viewType: string): Promise>; - async resolve(arg0: URI | IUntitledNotebookResource, viewType?: string): Promise> { + async resolve(resource: URI, viewType?: string, limits?: IFileReadLimits): Promise>; + async resolve(resource: IUntitledNotebookResource, viewType: string, limits?: IFileReadLimits): Promise>; + async resolve(arg0: URI | IUntitledNotebookResource, viewType?: string, limits?: IFileReadLimits): Promise> { let resource: URI; let hasAssociatedFilePath = false; if (URI.isUri(arg0)) { @@ -235,7 +236,7 @@ export class NotebookModelResolverServiceImpl implements INotebookEditorModelRes } } - const reference = this._data.acquire(resource.toString(), viewType, hasAssociatedFilePath); + const reference = this._data.acquire(resource.toString(), viewType, hasAssociatedFilePath, limits); try { const model = await reference.object; return { diff --git a/src/vs/workbench/contrib/notebook/test/browser/notebookCommon.test.ts b/src/vs/workbench/contrib/notebook/test/browser/notebookCommon.test.ts index 83d0164b035..476c7aa5327 100644 --- a/src/vs/workbench/contrib/notebook/test/browser/notebookCommon.test.ts +++ b/src/vs/workbench/contrib/notebook/test/browser/notebookCommon.test.ts @@ -305,6 +305,8 @@ suite('NotebookCommon', () => { suite('CellUri', function () { + ensureNoDisposablesAreLeakedInTestSuite(); + test('parse, generate (file-scheme)', function () { const nb = URI.parse('file:///bar/følder/file.nb'); @@ -348,6 +350,8 @@ suite('CellUri', function () { suite('CellRange', function () { + ensureNoDisposablesAreLeakedInTestSuite(); + test('Cell range to index', function () { assert.deepStrictEqual(cellRangesToIndexes([]), []); assert.deepStrictEqual(cellRangesToIndexes([{ start: 0, end: 0 }]), []); @@ -398,6 +402,7 @@ suite('CellRange', function () { }); suite('NotebookWorkingCopyTypeIdentifier', function () { + ensureNoDisposablesAreLeakedInTestSuite(); test('works', function () { const viewType = 'testViewType'; diff --git a/src/vs/workbench/contrib/notebook/test/browser/notebookSelection.test.ts b/src/vs/workbench/contrib/notebook/test/browser/notebookSelection.test.ts index b1aa61118fd..a45fd46828f 100644 --- a/src/vs/workbench/contrib/notebook/test/browser/notebookSelection.test.ts +++ b/src/vs/workbench/contrib/notebook/test/browser/notebookSelection.test.ts @@ -15,12 +15,15 @@ import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/uti import { DisposableStore } from 'vs/base/common/lifecycle'; suite('NotebookSelection', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + test('focus is never empty', function () { const selectionCollection = new NotebookCellSelectionCollection(); assert.deepStrictEqual(selectionCollection.focus, { start: 0, end: 0 }); selectionCollection.setState(null, [], true, 'model'); assert.deepStrictEqual(selectionCollection.focus, { start: 0, end: 0 }); + selectionCollection.dispose(); }); }); diff --git a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts index e953502efac..db3605eb6bd 100644 --- a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts +++ b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts @@ -27,6 +27,7 @@ import { isWeb } from 'vs/base/common/platform'; import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import * as perf from 'vs/base/common/performance'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration'; export class PerfviewContrib { @@ -59,7 +60,8 @@ export class PerfviewInput extends TextResourceEditorInput { @IEditorService editorService: IEditorService, @IFileService fileService: IFileService, @ILabelService labelService: ILabelService, - @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService ) { super( PerfviewInput.Uri, @@ -72,7 +74,8 @@ export class PerfviewInput extends TextResourceEditorInput { editorService, fileService, labelService, - filesConfigurationService + filesConfigurationService, + textResourceConfigurationService ); } } diff --git a/src/vs/workbench/contrib/remote/browser/media/remoteViewlet.css b/src/vs/workbench/contrib/remote/browser/media/remoteViewlet.css index ef32cf43f39..4ebb0d89702 100644 --- a/src/vs/workbench/contrib/remote/browser/media/remoteViewlet.css +++ b/src/vs/workbench/contrib/remote/browser/media/remoteViewlet.css @@ -13,7 +13,7 @@ flex-wrap: nowrap; } -.remote-help-content .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon { +.remote-help-content .monaco-list .monaco-list-row .remote-help-tree-node-item > .remote-help-tree-node-item-icon { background-size: 16px; background-position: left center; background-repeat: no-repeat; diff --git a/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts b/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts index c3b6b486a9f..17dc94277d9 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts @@ -85,13 +85,13 @@ export class SnippetCompletionProvider implements CompletionItemProvider { async provideCompletionItems(model: ITextModel, position: Position, context: CompletionContext): Promise { const sw = new StopWatch(); + const lineContentLow = model.getLineContent(position.lineNumber).toLowerCase(); + const wordUntil = model.getWordUntilPosition(position).word.toLowerCase(); + const languageId = this._getLanguageIdAtPosition(model, position); const languageConfig = this._languageConfigurationService.getLanguageConfiguration(languageId); const snippets = new Set(await this._snippets.getSnippets(languageId)); - const lineContentLow = model.getLineContent(position.lineNumber).toLowerCase(); - const wordUntil = model.getWordUntilPosition(position).word.toLowerCase(); - const suggestions: SnippetCompletion[] = []; const columnOffset = position.column - 1; diff --git a/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts b/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts index e74a499f9c0..084a9b64dde 100644 --- a/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts +++ b/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts @@ -819,4 +819,36 @@ suite('SnippetsService', function () { const first = result.suggestions[0]; assert.strictEqual((first.range).insert.startColumn, 5); }); + + test.skip('Autocomplete suggests based on the last letter of a word and it depends on the typing speed #191070', async function () { + snippetService = new SimpleSnippetService([ + new Snippet(false, ['fooLang'], '/whiletrue', '/whiletrue', '', 'one', '', SnippetSource.User, generateUuid()), + new Snippet(false, ['fooLang'], '/sc not expanding', '/sc not expanding', '', 'two', '', SnippetSource.User, generateUuid()), + ]); + + const provider = new SnippetCompletionProvider(languageService, snippetService, disposables.add(new TestLanguageConfigurationService())); + const model = disposables.add(instantiateTextModel(instantiationService, '', 'fooLang')); + + { // PREFIX: w + model.setValue('w'); + const result1 = await provider.provideCompletionItems( + model, + new Position(1, 2), + { triggerKind: CompletionTriggerKind.Invoke } + ); + assert.strictEqual(result1.suggestions.length, 1); + assert.strictEqual(result1.suggestions[0].insertText, 'one'); + } + + { // PREFIX: where + model.setValue('where'); + const result2 = await provider.provideCompletionItems( + model, + new Position(1, 6), + { triggerKind: CompletionTriggerKind.Invoke } + ); + assert.strictEqual(result2.suggestions.length, 1); + assert.strictEqual(result2.suggestions[1].insertText, 'one'); // /whiletrue matches where (WHilEtRuE) + } + }); }); diff --git a/src/vs/workbench/contrib/splash/browser/partsSplash.ts b/src/vs/workbench/contrib/splash/browser/partsSplash.ts index 60b8ea9abe1..1007270a967 100644 --- a/src/vs/workbench/contrib/splash/browser/partsSplash.ts +++ b/src/vs/workbench/contrib/splash/browser/partsSplash.ts @@ -7,7 +7,7 @@ import { onDidChangeFullscreen, isFullscreen } from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; import { Color } from 'vs/base/common/color'; import { Event } from 'vs/base/common/event'; -import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { editorBackground, foreground } from 'vs/platform/theme/common/colorRegistry'; import { getThemeTypeSelector, IThemeService } from 'vs/platform/theme/common/themeService'; import { DEFAULT_EDITOR_MIN_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor'; @@ -20,6 +20,7 @@ import * as perf from 'vs/base/common/performance'; import { assertIsDefined } from 'vs/base/common/types'; import { ISplashStorageService } from 'vs/workbench/contrib/splash/browser/splash'; import { mainWindow } from 'vs/base/browser/window'; +import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; export class PartsSplash { @@ -33,20 +34,24 @@ export class PartsSplash { @IThemeService private readonly _themeService: IThemeService, @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService, @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, - @IEditorGroupsService editorGroupsService: IEditorGroupsService, @IConfigurationService private readonly _configService: IConfigurationService, - @ISplashStorageService private readonly _partSplashService: ISplashStorageService + @ISplashStorageService private readonly _partSplashService: ISplashStorageService, + @IEditorGroupsService editorGroupsService: IEditorGroupsService, + @ILifecycleService lifecycleService: ILifecycleService, ) { Event.once(_layoutService.onDidLayoutMainContainer)(() => { this._removePartsSplash(); perf.mark('code/didRemovePartsSplash'); }, undefined, this._disposables); - let lastIdleSchedule: IDisposable | undefined; - Event.any(onDidChangeFullscreen, editorGroupsService.mainPart.onDidLayout, _themeService.onDidColorThemeChange)(() => { - lastIdleSchedule?.dispose(); - lastIdleSchedule = dom.runWhenWindowIdle(mainWindow, () => this._savePartsSplash(), 800); - }, undefined, this._disposables); + const lastIdleSchedule = this._disposables.add(new MutableDisposable()); + const savePartsSplashSoon = () => { + lastIdleSchedule.value = dom.runWhenWindowIdle(mainWindow, () => this._savePartsSplash(), 2500); + }; + lifecycleService.when(LifecyclePhase.Restored).then(() => { + Event.any(onDidChangeFullscreen, editorGroupsService.mainPart.onDidLayout, _themeService.onDidColorThemeChange)(savePartsSplashSoon, undefined, this._disposables); + savePartsSplashSoon(); + }); _configService.onDidChangeConfiguration(e => { if (e.affectsConfiguration('window.titleBarStyle')) { diff --git a/src/vs/workbench/contrib/tags/test/node/workspaceTags.test.ts b/src/vs/workbench/contrib/tags/test/node/workspaceTags.test.ts index ff3d16fd312..7f58ae8e9e1 100644 --- a/src/vs/workbench/contrib/tags/test/node/workspaceTags.test.ts +++ b/src/vs/workbench/contrib/tags/test/node/workspaceTags.test.ts @@ -5,6 +5,7 @@ import * as assert from 'assert'; import * as crypto from 'crypto'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { getHashedRemotesFromConfig as baseGetHashedRemotesFromConfig } from 'vs/workbench/contrib/tags/common/workspaceTags'; function hash(value: string): string { @@ -58,4 +59,6 @@ suite('Telemetry - WorkspaceTags', () => { fetch = +refs/heads/*:refs/remotes/origin/* `; } + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh index 50ea1e39a52..b64082777be 100755 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh @@ -256,8 +256,8 @@ else __vsc_preexec_all() { if [ "$__vsc_in_command_execution" = "0" ]; then __vsc_in_command_execution="1" - builtin eval "${__vsc_dbg_trap}" __vsc_preexec + builtin eval "${__vsc_dbg_trap}" fi } trap '__vsc_preexec_all "$_"' DEBUG diff --git a/src/vs/workbench/contrib/terminal/common/terminalColorRegistry.ts b/src/vs/workbench/contrib/terminal/common/terminalColorRegistry.ts index 15e5cef62aa..34fa7dea75f 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalColorRegistry.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalColorRegistry.ts @@ -77,7 +77,7 @@ export const TERMINAL_FIND_MATCH_BACKGROUND_COLOR = registerColor('terminal.find // Use regular selection background in high contrast with a thick border hcDark: null, hcLight: '#0F4A85' -}, nls.localize('terminal.findMatchBackground', 'Color of the current search match in the terminal. The color must not be opaque so as not to hide underlying terminal content.')); +}, nls.localize('terminal.findMatchBackground', 'Color of the current search match in the terminal. The color must not be opaque so as not to hide underlying terminal content.'), true); export const TERMINAL_HOVER_HIGHLIGHT_BACKGROUND_COLOR = registerColor('terminal.hoverHighlightBackground', { dark: transparent(editorHoverHighlight, 0.5), light: transparent(editorHoverHighlight, 0.5), @@ -95,7 +95,7 @@ export const TERMINAL_FIND_MATCH_HIGHLIGHT_BACKGROUND_COLOR = registerColor('ter light: editorFindMatchHighlight, hcDark: null, hcLight: null -}, nls.localize('terminal.findMatchHighlightBackground', 'Color of the other search matches in the terminal. The color must not be opaque so as not to hide underlying terminal content.')); +}, nls.localize('terminal.findMatchHighlightBackground', 'Color of the other search matches in the terminal. The color must not be opaque so as not to hide underlying terminal content.'), true); export const TERMINAL_FIND_MATCH_HIGHLIGHT_BORDER_COLOR = registerColor('terminal.findMatchHighlightBorder', { dark: null, light: null, @@ -113,7 +113,7 @@ export const TERMINAL_DRAG_AND_DROP_BACKGROUND = registerColor('terminal.dropBac light: EDITOR_DRAG_AND_DROP_BACKGROUND, hcDark: EDITOR_DRAG_AND_DROP_BACKGROUND, hcLight: EDITOR_DRAG_AND_DROP_BACKGROUND -}, nls.localize('terminal.dragAndDropBackground', "Background color when dragging on top of terminals. The color should have transparency so that the terminal contents can still shine through.")); +}, nls.localize('terminal.dragAndDropBackground', "Background color when dragging on top of terminals. The color should have transparency so that the terminal contents can still shine through."), true); export const TERMINAL_TAB_ACTIVE_BORDER = registerColor('terminal.tab.activeBorder', { dark: TAB_ACTIVE_BORDER, light: TAB_ACTIVE_BORDER, diff --git a/src/vs/workbench/contrib/themes/test/node/colorRegistryExport.test.ts b/src/vs/workbench/contrib/themes/test/node/colorRegistryExport.test.ts index a051fa3ae71..ccd7af54f75 100644 --- a/src/vs/workbench/contrib/themes/test/node/colorRegistryExport.test.ts +++ b/src/vs/workbench/contrib/themes/test/node/colorRegistryExport.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Color } from 'vs/base/common/color'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions, IColorRegistry } from 'vs/platform/theme/common/colorRegistry'; @@ -17,4 +18,6 @@ suite('ColorRegistry', () => { console.log(`#colors:${JSON.stringify(colors, replacer)}\n`); }); } + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/workbench/contrib/url/test/browser/trustedDomains.test.ts b/src/vs/workbench/contrib/url/test/browser/trustedDomains.test.ts index 898f6af547d..2d34fee58f6 100644 --- a/src/vs/workbench/contrib/url/test/browser/trustedDomains.test.ts +++ b/src/vs/workbench/contrib/url/test/browser/trustedDomains.test.ts @@ -8,6 +8,7 @@ import * as assert from 'assert'; import { isURLDomainTrusted } from 'vs/workbench/contrib/url/browser/trustedDomainsValidator'; import { URI } from 'vs/base/common/uri'; import { extractGitHubRemotesFromGitConfig } from 'vs/workbench/contrib/url/browser/trustedDomains'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; function linkAllowedByRules(link: string, rules: string[]) { assert.ok(isURLDomainTrusted(URI.parse(link), rules), `Link\n${link}\n should be allowed by rules\n${JSON.stringify(rules)}`); @@ -17,6 +18,7 @@ function linkNotAllowedByRules(link: string, rules: string[]) { } suite('GitHub remote extraction', () => { + ensureNoDisposablesAreLeakedInTestSuite(); test('All known formats', () => { assert.deepStrictEqual( extractGitHubRemotesFromGitConfig( @@ -39,6 +41,7 @@ suite('GitHub remote extraction', () => { }); suite('Link protection domain matching', () => { + ensureNoDisposablesAreLeakedInTestSuite(); test('simple', () => { linkNotAllowedByRules('https://x.org', []); diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css b/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css index 0790a628607..2a31a8ba681 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css @@ -8,7 +8,7 @@ background-image: url('../../../../browser/media/code-icon.svg'); } -.monaco-workbench .part.editor>.content .gettingStartedContainer { +.monaco-workbench .part.editor > .content .gettingStartedContainer { box-sizing: border-box; line-height: 22px; position: relative; @@ -20,26 +20,26 @@ outline: none; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.loading { +.monaco-workbench .part.editor > .content .gettingStartedContainer.loading { display: none; } -.monaco-workbench .part.editor>.content .gettingStartedContainer img { +.monaco-workbench .part.editor > .content .gettingStartedContainer img { max-width: 100%; max-height: 100%; object-fit: contain; pointer-events: none; } -.monaco-workbench .part.editor>.content .gettingStartedContainer { +.monaco-workbench .part.editor > .content .gettingStartedContainer { font-size: 13px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStarted { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStarted { height: 100%; } -.monaco-workbench .part.editor>.content .gettingStartedContainer h1 { +.monaco-workbench .part.editor > .content .gettingStartedContainer h1 { padding: 5px 0 0; margin: 0; border: none; @@ -48,24 +48,24 @@ white-space: nowrap; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .title { +.monaco-workbench .part.editor > .content .gettingStartedContainer .title { margin-top: 1em; margin-bottom: 1em; flex: 1 100%; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .subtitle { +.monaco-workbench .part.editor > .content .gettingStartedContainer .subtitle { margin-top: .6em; font-size: 2em; display: block; } -.monaco-workbench.hc-black .part.editor>.content .gettingStartedContainer .subtitle, -.monaco-workbench.hc-light .part.editor>.content .gettingStartedContainer .subtitle { +.monaco-workbench.hc-black .part.editor > .content .gettingStartedContainer .subtitle, +.monaco-workbench.hc-light .part.editor > .content .gettingStartedContainer .subtitle { font-weight: 200; } -.monaco-workbench .part.editor>.content .gettingStartedContainer h2 { +.monaco-workbench .part.editor > .content .gettingStartedContainer h2 { font-weight: 400; margin-top: 0; margin-bottom: 5px; @@ -73,12 +73,12 @@ line-height: initial; } -.monaco-workbench .part.editor>.content .gettingStartedContainer a:focus { +.monaco-workbench .part.editor > .content .gettingStartedContainer a:focus { outline: 1px solid -webkit-focus-ring-color; outline-offset: -1px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide { width: 100%; height: 100%; padding: 0; @@ -88,23 +88,23 @@ top: 0; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories { padding: 12px 24px; } /* duplicated until the getting-started specific setting is removed */ -.monaco-workbench .part.editor>.content .gettingStartedContainer.animatable .gettingStartedSlide { +.monaco-workbench .part.editor > .content .gettingStartedContainer.animatable .gettingStartedSlide { /* keep consistant with SLIDE_TRANSITION_TIME_MS in gettingStarted.ts */ transition: left 0.25s, opacity 0.25s; } -.monaco-workbench.reduce-motion .part.editor>.content .gettingStartedContainer .gettingStartedSlide, -.monaco-workbench.reduce-motion .part.editor>.content .gettingStartedContainer.animatable .gettingStartedSlide { +.monaco-workbench.reduce-motion .part.editor > .content .gettingStartedContainer .gettingStartedSlide, +.monaco-workbench.reduce-motion .part.editor > .content .gettingStartedContainer.animatable .gettingStartedSlide { /* keep consistant with SLIDE_TRANSITION_TIME_MS in gettingStarted.ts */ transition: left 0.0s, opacity 0.0s; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories>.gettingStartedCategoriesContainer { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer { display: grid; height: 100%; max-width: 1200px; @@ -117,73 +117,73 @@ ". footer footer footer ."; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.width-constrained .gettingStartedSlideCategories>.gettingStartedCategoriesContainer { +.monaco-workbench .part.editor > .content .gettingStartedContainer.width-constrained .gettingStartedSlideCategories > .gettingStartedCategoriesContainer { grid-template-rows: auto min-content minmax(min-content, auto) min-content; grid-template-columns: 1fr; grid-template-areas: "header" "left-column" "right-column" "footer"; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.height-constrained .gettingStartedSlideCategories>.gettingStartedCategoriesContainer { +.monaco-workbench .part.editor > .content .gettingStartedContainer.height-constrained .gettingStartedSlideCategories > .gettingStartedCategoriesContainer { grid-template-rows: auto minmax(min-content, auto) min-content; grid-template-areas: "header" "left-column right-column" "footer footer"; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.height-constrained.width-constrained .gettingStartedSlideCategories>.gettingStartedCategoriesContainer { +.monaco-workbench .part.editor > .content .gettingStartedContainer.height-constrained.width-constrained .gettingStartedSlideCategories > .gettingStartedCategoriesContainer { grid-template-rows: min-content minmax(min-content, auto) min-content; grid-template-columns: 1fr; grid-template-areas: "left-column" "right-column" "footer"; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.width-constrained .gettingStartedSlideCategories>.gettingStartedCategoriesContainer>.header, .monaco-workbench .part.editor>.content .gettingStartedContainer.height-constrained .gettingStartedSlideCategories>.gettingStartedCategoriesContainer>.header { +.monaco-workbench .part.editor > .content .gettingStartedContainer.width-constrained .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .header, .monaco-workbench .part.editor > .content .gettingStartedContainer.height-constrained .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .header { display: none; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories li.showWalkthroughsEntry { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories li.showWalkthroughsEntry { display: none; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.noWalkthroughs .gettingStartedSlideCategories li.showWalkthroughsEntry, .gettingStartedContainer.noExtensions { +.monaco-workbench .part.editor > .content .gettingStartedContainer.noWalkthroughs .gettingStartedSlideCategories li.showWalkthroughsEntry, .gettingStartedContainer.noExtensions { display: unset; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories>.gettingStartedCategoriesContainer>* { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > * { overflow: hidden; text-overflow: ellipsis; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories>.gettingStartedCategoriesContainer>.categories-column>div { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .categories-column > div { margin-bottom: 32px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories>.gettingStartedCategoriesContainer>.categories-column-left { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .categories-column-left { grid-area: left-column; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories>.gettingStartedCategoriesContainer>.categories-column-right { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .categories-column-right { grid-area: right-column; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories>.gettingStartedCategoriesContainer>.header { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .header { grid-area: header; align-self: end; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories>.gettingStartedCategoriesContainer>.footer { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .footer { grid-area: footer; justify-self: center; text-align: center; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .categories-slide-container { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .categories-slide-container { width: 90%; max-width: 1200px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .gap { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .gap { flex: 150px 0 1000 } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .category-title { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .category-title { margin: 4px 0 4px; font-size: 14px; font-weight: 500; @@ -194,58 +194,58 @@ white-space: nowrap; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .category-progress { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .category-progress { position: absolute; bottom: 0; left: 0; width: 100%; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category.no-progress { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category.no-progress { padding: 3px 6px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .getting-started-category.no-progress .category-progress { +.monaco-workbench .part.editor > .content .gettingStartedContainer .getting-started-category.no-progress .category-progress { display: none; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories ul { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories ul { list-style: none; margin: 0; line-height: 24px; padding-left: 0; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories li { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories li { list-style: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .path { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .path { padding-left: 1em; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .icon-widget, -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .icon-widget, -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .featured-icon { +.monaco-workbench .part.editor > .content .gettingStartedContainer .icon-widget, +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .icon-widget, +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .featured-icon { font-size: 20px; padding-right: 8px; position: relative; top: 3px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .codicon:not(.icon-widget, .featured-icon, .hide-category-button) { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .codicon:not(.icon-widget, .featured-icon, .hide-category-button) { margin: 0 2px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .codicon:first-child { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .codicon:first-child { margin-left: 0; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .start-container img { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .start-container img { padding-right: 8px; position: relative; top: 3px; @@ -253,20 +253,20 @@ max-height: 16px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .keybinding-label { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .keybinding-label { padding-left: 1em; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .progress-bar-outer { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .progress-bar-outer { height: 4px; margin-top: 4px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .progress-bar-inner { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .progress-bar-inner { height: 100%; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category { width: calc(100% - 16px); font-size: 13px; box-sizing: border-box; @@ -276,36 +276,36 @@ text-align: left; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .getting-started-category { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .getting-started-category { position: relative; border-radius: 6px; overflow: hidden; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .main-content { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .main-content { display: flex; align-items: center; justify-content: flex-start; width: 100%; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .featured-description-content, -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .description-content { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .featured-description-content, +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .description-content { text-align: left; margin-left: 28px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .description-content > .codicon { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .description-content > .codicon { padding-right: 1px; font-size: 16px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .description-content:not(:empty){ +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .description-content:not(:empty){ margin-bottom: 8px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .featured-description-content:not(:empty){ +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .featured-description-content:not(:empty){ margin-bottom: 8px; margin-left: 32px; overflow: hidden; @@ -314,7 +314,7 @@ -webkit-box-orient: vertical; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .new-badge { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .new-badge { justify-self: flex-end; align-self: flex-start; border-radius: 4px; @@ -324,13 +324,13 @@ white-space: nowrap; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .featured-badge { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .featured-badge { position: relative; top: -4px; left: -8px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .featured { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .featured { border-top: 30px solid var(--vscode-activityBarBadge-background); width: 30px; box-sizing: border-box; @@ -339,23 +339,23 @@ position: absolute; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .featured .featured-icon { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .featured .featured-icon { top: -30px; left: 4px; font-size: 14px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .codicon.hide-category-button { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .codicon.hide-category-button { margin-left: auto; top: 4px; right: 8px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category.featured .icon-widget { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category.featured .icon-widget { visibility: hidden; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .getting-started-category img.category-icon { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .getting-started-category img.category-icon { padding-right: 8px; max-width: 20px; max-height: 20px; @@ -363,7 +363,7 @@ top: auto; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories .getting-started-category img.featured-icon { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories .getting-started-category img.featured-icon { padding-right: 8px; max-width: 24px; max-height: 24px; @@ -371,80 +371,80 @@ position: relative; top: auto; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-category img.category-icon { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-category img.category-icon { margin-right: 10px; margin-left: 10px; max-width: 32px; max-height: 32px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails { display: flex; flex-direction: column; overflow: hidden; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .gap { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .gap { flex: 150px 0 1000 } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-category { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-category { display: flex; margin-bottom: 24px; min-height: auto; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-columns .gap { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-columns .gap { flex: 150px 1 1000 } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent>.getting-started-category>.codicon-getting-started-setup { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent > .getting-started-category > .codicon-getting-started-setup { margin-right: 8px; font-size: 28px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-columns { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-columns { display: flex; justify-content: flex-start; padding: 40px 40px 0; max-height: calc(100% - 40px); } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step { display: flex; width: 100%; overflow: hidden; border-radius: 6px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .button-container:not(:last-of-type) { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .button-container:not(:last-of-type) { margin-bottom: 6px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step.expanded { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step.expanded { cursor: default !important; border: 1px solid var(--vscode-welcomePage-tileBorder); } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step.expanded h3 { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step.expanded h3 { color: var(--vscode-walkthrough-stepTitle-foreground); } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step.expanded>.codicon { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step.expanded > .codicon { cursor: pointer !important; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step:not(.expanded) { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step:not(.expanded) { height: 48px; background: none; color: var(--vscode-descriptionForeground); } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step:not(.expanded):hover { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step:not(.expanded):hover { background: var(--vscode-welcomePage-tileHoverBackground); } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step:not(.expanded) .step-title { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step:not(.expanded) .step-title { white-space: nowrap; text-overflow: ellipsis; display: inline-block; @@ -452,66 +452,66 @@ width: inherit; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-title .codicon { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-title .codicon { position: relative; top: 2px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-columns .getting-started-detail-left>div { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-columns .getting-started-detail-left > div { width: 100%; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step:not(.expanded) .step-description-container { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step:not(.expanded) .step-description-container { visibility: hidden; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-container { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-container { width: 100%; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-description { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-description { padding-top: 8px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .actions { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .actions { margin-top: 12px; display: flex; align-items: center; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .shortcut-message { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .shortcut-message { display: flex; color: var(--vscode-descriptionForeground); font-size: 12px; margin-top: 12px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .shortcut-message .keybinding { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .shortcut-message .keybinding { font-weight: 600; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-next { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-next { margin-left: auto; margin-right: 10px; padding: 6px 12px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .codicon.hidden { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .codicon.hidden { display: none; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .codicon-getting-started-step-unchecked, -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .codicon-getting-started-step-checked { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .codicon-getting-started-step-unchecked, +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .codicon-getting-started-step-checked { margin-right: 8px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step-action { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step-action { padding: 6px 12px; font-size: 13px; margin-bottom: 0; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-left { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-left { min-width: 330px; width: 40%; max-width: 400px; @@ -519,15 +519,15 @@ flex-direction: column; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .full-height-scrollable { +.monaco-workbench .part.editor > .content .gettingStartedContainer .full-height-scrollable { height: 100%; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-container { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-container { height: 100%; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent { height: 100%; max-width: 1200px; margin: 0 auto; @@ -543,7 +543,7 @@ ". footer footer footer ."; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.width-semi-constrained .gettingStartedSlideDetails .gettingStartedDetailsContent { +.monaco-workbench .part.editor > .content .gettingStartedContainer.width-semi-constrained .gettingStartedSlideDetails .gettingStartedDetailsContent { max-width: 500px; grid-template-columns: auto; grid-template-rows: 30px max-content minmax(30%, max-content) minmax(30%, 1fr) auto; @@ -551,45 +551,45 @@ grid-template-areas: "back" "title" "steps" "media" "footer"; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.width-semi-constrained .gettingStartedSlideDetails .gettingStartedDetailsContent.markdown { +.monaco-workbench .part.editor > .content .gettingStartedContainer.width-semi-constrained .gettingStartedSlideDetails .gettingStartedDetailsContent.markdown { grid-template-rows: 30px max-content minmax(30%, max-content) minmax(40%, 1fr) auto; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.width-semi-constrained.height-constrained .gettingStartedSlideDetails .gettingStartedDetailsContent { +.monaco-workbench .part.editor > .content .gettingStartedContainer.width-semi-constrained.height-constrained .gettingStartedSlideDetails .gettingStartedDetailsContent { grid-template-rows: 0 max-content minmax(25%, max-content) minmax(25%, 1fr) auto; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent>.prev-button { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent > .prev-button { grid-area: back; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent>.getting-started-category { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent > .getting-started-category { grid-area: title; align-self: flex-end; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent>.steps-container { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent > .steps-container { height: 100%; grid-area: steps; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent>.getting-started-media { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent > .getting-started-media { grid-area: media; align-self: center; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent.markdown>.getting-started-media { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent.markdown > .getting-started-media { height: inherit; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent.image>.getting-started-media { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent.image > .getting-started-media { grid-area: title-start / media-start / steps-end / media-end; align-self: unset; display: flex; justify-content: center; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.width-semi-constrained .gettingStartedSlideDetails .gettingStartedDetailsContent.image>.getting-started-media { +.monaco-workbench .part.editor > .content .gettingStartedContainer.width-semi-constrained .gettingStartedSlideDetails .gettingStartedDetailsContent.image > .getting-started-media { grid-area: media; height: inherit; width: inherit; @@ -597,14 +597,14 @@ justify-content: center; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent>.getting-started-footer { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .gettingStartedDetailsContent > .getting-started-footer { grid-area: footer; align-self: flex-end; justify-self: center; text-align: center; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-right { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-right { display: flex; align-items: flex-start; justify-content: center; @@ -615,36 +615,36 @@ max-width: 800px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .index-list.getting-started .button-link { +.monaco-workbench .part.editor > .content .gettingStartedContainer .index-list.getting-started .button-link { margin: 0; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .index-list.getting-started .see-all-walkthroughs { +.monaco-workbench .part.editor > .content .gettingStartedContainer .index-list.getting-started .see-all-walkthroughs { display: none; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.someWalkthroughsHidden .index-list.getting-started .see-all-walkthroughs { +.monaco-workbench .part.editor > .content .gettingStartedContainer.someWalkthroughsHidden .index-list.getting-started .see-all-walkthroughs { display: inline; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.noExtensions .index-list.featured-extensions { +.monaco-workbench .part.editor > .content .gettingStartedContainer.noExtensions .index-list.featured-extensions { display: none; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.noWalkthroughs .index-list.getting-started { +.monaco-workbench .part.editor > .content .gettingStartedContainer.noWalkthroughs .index-list.getting-started { display: none; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-right img { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-right img { object-fit: contain; cursor: unset; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-right img.clickable { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-detail-right img.clickable { cursor: pointer; } -.monaco-workbench .part.editor>.content .gettingStartedContainer button { +.monaco-workbench .part.editor > .content .gettingStartedContainer button { border: none; color: inherit; text-align: left; @@ -655,21 +655,21 @@ font-family: inherit; } -.monaco-workbench .part.editor>.content .gettingStartedContainer button:hover { +.monaco-workbench .part.editor > .content .gettingStartedContainer button:hover { cursor: pointer; } /* Don't show focus outline on mouse click. Instead only show outline on keyboard focus. */ -.monaco-workbench .part.editor>.content .gettingStartedContainer button:focus { +.monaco-workbench .part.editor > .content .gettingStartedContainer button:focus { outline: none; } -.monaco-workbench .part.editor>.content .gettingStartedContainer button:focus-visible { +.monaco-workbench .part.editor > .content .gettingStartedContainer button:focus-visible { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .prev-button.button-link { +.monaco-workbench .part.editor > .content .gettingStartedContainer .prev-button.button-link { position: absolute; left: 40px; top: 5px; @@ -679,91 +679,91 @@ display: none; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.width-semi-constrained .prev-button.button-link { +.monaco-workbench .part.editor > .content .gettingStartedContainer.width-semi-constrained .prev-button.button-link { left: 0; top: -10px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.height-constrained .prev-button.button-link { +.monaco-workbench .part.editor > .content .gettingStartedContainer.height-constrained .prev-button.button-link { left: 0; top: -10px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.height-constrained .prev-button.button-link .codicon { +.monaco-workbench .part.editor > .content .gettingStartedContainer.height-constrained .prev-button.button-link .codicon { font-size: 20px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer.height-constrained .prev-button.button-link .moreText { +.monaco-workbench .part.editor > .content .gettingStartedContainer.height-constrained .prev-button.button-link .moreText { display: none; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .prev-button:hover { +.monaco-workbench .part.editor > .content .gettingStartedContainer .prev-button:hover { cursor: pointer; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .prev-button .codicon { +.monaco-workbench .part.editor > .content .gettingStartedContainer .prev-button .codicon { position: relative; top: 3px; left: -4px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .button-link .codicon-arrow-right { +.monaco-workbench .part.editor > .content .gettingStartedContainer .button-link .codicon-arrow-right { padding-left: 4px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .button-link .codicon-check-all { +.monaco-workbench .part.editor > .content .gettingStartedContainer .button-link .codicon-check-all { padding-right: 4px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .skip { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .skip { display: block; margin: 2px auto; width: fit-content; text-align: center; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails h2 { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails h2 { font-size: 26px; font-weight: normal; margin: 0 0 8px 0; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails h2 .codicon { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails h2 .codicon { font-size: 20px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails h3 { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails h3 { font-size: 13px; font-weight: 600; margin: 0; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .subtitle { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .subtitle { font-size: 16px; margin: 0; padding: 0; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStarted.showCategories .gettingStartedSlideDetails { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStarted.showCategories .gettingStartedSlideDetails { left: 100%; opacity: 0; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStarted.showDetails .gettingStartedSlideCategories { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStarted.showDetails .gettingStartedSlideCategories { left: -100%; opacity: 0; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStarted.showDetails .categoriesScrollbar .scrollbar.vertical { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStarted.showDetails .categoriesScrollbar .scrollbar.vertical { display: none; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .done-next-container { +.monaco-workbench .part.editor > .content .gettingStartedContainer .done-next-container { display: flex; padding: 16px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .button-link { +.monaco-workbench .part.editor > .content .gettingStartedContainer .button-link { padding: 0; background: transparent; margin: 2px; @@ -773,20 +773,20 @@ max-width: 100%; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .done-next-container .button-link { +.monaco-workbench .part.editor > .content .gettingStartedContainer .done-next-container .button-link { display: flex; align-items: center; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .button-link.next { +.monaco-workbench .part.editor > .content .gettingStartedContainer .button-link.next { margin-left: auto; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .button-link:hover { +.monaco-workbench .part.editor > .content .gettingStartedContainer .button-link:hover { background: transparent; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .openAWalkthrough>button, .monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .showOnStartup { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .openAWalkthrough > button, .monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .showOnStartup { text-align: center; display: flex; justify-content: center; @@ -794,7 +794,7 @@ gap: 8px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox { color: inherit !important; height: 18px; width: 18px; @@ -805,45 +805,45 @@ } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox.codicon:not(.checked)::before { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox.codicon:not(.checked)::before { opacity: 0; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories>.gettingStartedCategoriesContainer>.footer p { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .footer p { margin: 0; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories>.gettingStartedCategoriesContainer .index-list.start-container { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer .index-list.start-container { min-height: 156px; margin-bottom: 16px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideCategories>.gettingStartedCategoriesContainer>.footer>button { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .footer > button { text-align: center; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .getting-started-category .codicon { +.monaco-workbench .part.editor > .content .gettingStartedContainer .getting-started-category .codicon { top: 0px; } -.monaco-workbench .part.editor>.content .getting-started-category .codicon-star-full::before { +.monaco-workbench .part.editor > .content .getting-started-category .codicon-star-full::before { vertical-align: middle; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .hide-category-button { +.monaco-workbench .part.editor > .content .gettingStartedContainer .hide-category-button { visibility: hidden; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .getting-started-category:focus-within .hide-category-button, -.monaco-workbench .part.editor>.content .gettingStartedContainer .getting-started-category:hover .hide-category-button { +.monaco-workbench .part.editor > .content .gettingStartedContainer .getting-started-category:focus-within .hide-category-button, +.monaco-workbench .part.editor > .content .gettingStartedContainer .getting-started-category:hover .hide-category-button { visibility: visible; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-description-container span { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-description-container span { line-height: 1.3em; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-description-container .monaco-button, .monaco-workbench .part.editor>.content .gettingStartedContainer .max-lines-3 { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-description-container .monaco-button, .monaco-workbench .part.editor > .content .gettingStartedContainer .max-lines-3 { /* Supported everywhere: https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-line-clamp#browser_compatibility */ -webkit-line-clamp: 3; display: -webkit-box; @@ -851,7 +851,7 @@ overflow: hidden; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-description-container .monaco-button { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-description-container .monaco-button { height: 24px; width: fit-content; display: flex; @@ -860,16 +860,16 @@ min-width: max-content; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .hide-category-button { +.monaco-workbench .part.editor > .content .gettingStartedContainer .hide-category-button { padding: 3px; border-radius: 5px; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .hide-category-button::before { +.monaco-workbench .part.editor > .content .gettingStartedContainer .hide-category-button::before { vertical-align: unset; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .hide-category-button:hover { +.monaco-workbench .part.editor > .content .gettingStartedContainer .hide-category-button:hover { background-color: var(--vscode-toolbar-hoverBackground); } @@ -980,26 +980,26 @@ background-color: var(--vscode-welcomePage-progress-foreground); } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .new-badge { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .new-badge { color: var(--vscode-activityBarBadge-foreground); } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .featured .featured-icon { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .featured .featured-icon { color: var(--vscode-activityBarBadge-foreground); } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .new-badge { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .new-badge { background-color: var(--vscode-activityBarBadge-background); } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox { background-color: var(--vscode-checkbox-background) !important; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox { color: var(--vscode-checkbox-foreground) !important; } -.monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox { +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox { border-color: var(--vscode-checkbox-border) !important; } diff --git a/src/vs/workbench/contrib/welcomeWalkthrough/browser/media/walkThroughPart.css b/src/vs/workbench/contrib/welcomeWalkthrough/browser/media/walkThroughPart.css index 22cacd37226..ed362ff32c5 100644 --- a/src/vs/workbench/contrib/welcomeWalkthrough/browser/media/walkThroughPart.css +++ b/src/vs/workbench/contrib/welcomeWalkthrough/browser/media/walkThroughPart.css @@ -159,7 +159,7 @@ border-color: var(--vscode-contrastBorder); } -.monaco-workbench .part.editor>.content .walkThroughContent .monaco-editor-background, -.monaco-workbench .part.editor>.content .walkThroughContent .margin-view-overlays { +.monaco-workbench .part.editor > .content .walkThroughContent .monaco-editor-background, +.monaco-workbench .part.editor > .content .walkThroughContent .margin-view-overlays { background: var(--vscode-walkThrough-embeddedEditorBackground); } diff --git a/src/vs/workbench/electron-sandbox/desktop.contribution.ts b/src/vs/workbench/electron-sandbox/desktop.contribution.ts index f904efaafae..4a7fe629e12 100644 --- a/src/vs/workbench/electron-sandbox/desktop.contribution.ts +++ b/src/vs/workbench/electron-sandbox/desktop.contribution.ts @@ -151,6 +151,11 @@ import { applicationConfigurationNodeBase, securityConfigurationNodeBase } from 'title': localize('windowConfigurationTitle', "Window"), 'type': 'object', 'properties': { + 'window.confirmSaveUntitledWorkspace': { + 'type': 'boolean', + 'default': true, + 'description': localize('confirmSaveUntitledWorkspace', "Controls whether a confirmation dialog shows asking to save or discard an opened untitled workspace in the window when switching to another workspace."), + }, 'window.openWithoutArgumentsInNewWindow': { 'type': 'string', 'enum': ['on', 'off'], diff --git a/src/vs/workbench/services/configurationResolver/test/electron-sandbox/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/electron-sandbox/configurationResolverService.test.ts index a2d2aa43af0..7357382e7a3 100644 --- a/src/vs/workbench/services/configurationResolver/test/electron-sandbox/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/electron-sandbox/configurationResolverService.test.ts @@ -12,6 +12,7 @@ import { IPath, normalize } from 'vs/base/common/path'; import * as platform from 'vs/base/common/platform'; import { isObject } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { Selection } from 'vs/editor/common/core/selection'; import { EditorType } from 'vs/editor/common/editorCommon'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -645,6 +646,8 @@ suite('Configuration Resolver Service', () => { const resolvedResult = await configurationResolverService!.resolveWithEnvironment({ ...env }, undefined, configuration); assert.deepStrictEqual(resolvedResult, 'echo VAL_1VAL_2'); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/workbench/services/editor/browser/editorResolverService.ts b/src/vs/workbench/services/editor/browser/editorResolverService.ts index 6e3c55e4cc6..91d1b7f6da9 100644 --- a/src/vs/workbench/services/editor/browser/editorResolverService.ts +++ b/src/vs/workbench/services/editor/browser/editorResolverService.ts @@ -276,11 +276,12 @@ export class EditorResolverService extends Disposable implements IEditorResolver getAllUserAssociations(): EditorAssociations { const inspectedEditorAssociations = this.configurationService.inspect<{ [fileNamePattern: string]: string }>(editorsAssociationsSettingId) || {}; + const defaultAssociations = inspectedEditorAssociations.defaultValue ?? {}; const workspaceAssociations = inspectedEditorAssociations.workspaceValue ?? {}; const userAssociations = inspectedEditorAssociations.userValue ?? {}; const rawAssociations: { [fileNamePattern: string]: string } = { ...workspaceAssociations }; - // We want to apply the user associations on top of the workspace associations but ignore duplicate keys. - for (const [key, value] of Object.entries(userAssociations)) { + // We want to apply the default associations and user associations on top of the workspace associations but ignore duplicate keys. + for (const [key, value] of Object.entries({ ...defaultAssociations, ...userAssociations })) { if (rawAssociations[key] === undefined) { rawAssociations[key] = value; } diff --git a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts index e3c810e97a2..db455b09007 100644 --- a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts @@ -180,7 +180,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { const result = await this.dialogService.confirm({ message: localize('confirmUrl', "Allow '{0}' extension to open this URI?", extensionDisplayName), checkbox: { - label: localize('rememberConfirmUrl', "Don't ask again for this extension."), + label: localize('rememberConfirmUrl', "Do not ask me again for this extension"), }, detail: uriString, primaryButton: localize({ key: 'open', comment: ['&& denotes a mnemonic'] }, "&&Open") diff --git a/src/vs/workbench/services/label/test/browser/label.test.ts b/src/vs/workbench/services/label/test/browser/label.test.ts index 520ed89e35d..f5098c5df72 100644 --- a/src/vs/workbench/services/label/test/browser/label.test.ts +++ b/src/vs/workbench/services/label/test/browser/label.test.ts @@ -28,6 +28,8 @@ suite('URI Label', () => { labelService = new LabelService(TestEnvironmentService, new TestContextService(), new TestPathService(URI.file('/foobar')), new TestRemoteAgentService(), storageService, new TestLifecycleService()); }); + ensureNoDisposablesAreLeakedInTestSuite(); + test('custom scheme', function () { labelService.registerFormatter({ scheme: 'vscode', diff --git a/src/vs/workbench/services/search/test/node/textSearchManager.test.ts b/src/vs/workbench/services/search/test/node/textSearchManager.test.ts index fec67730fa0..f4203933951 100644 --- a/src/vs/workbench/services/search/test/node/textSearchManager.test.ts +++ b/src/vs/workbench/services/search/test/node/textSearchManager.test.ts @@ -6,6 +6,7 @@ import * as assert from 'assert'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { URI } from 'vs/base/common/uri'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { Progress } from 'vs/platform/progress/common/progress'; import { ITextQuery, QueryType } from 'vs/workbench/services/search/common/search'; import { ProviderResult, TextSearchComplete, TextSearchOptions, TextSearchProvider, TextSearchQuery, TextSearchResult } from 'vs/workbench/services/search/common/searchExtTypes'; @@ -38,4 +39,6 @@ suite('NativeTextSearchManager', () => { assert.ok(correctEncoding); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/workbench/services/suggest/browser/media/suggest.css b/src/vs/workbench/services/suggest/browser/media/suggest.css index 730b6fe66d5..366f7b7d6fd 100644 --- a/src/vs/workbench/services/suggest/browser/media/suggest.css +++ b/src/vs/workbench/services/suggest/browser/media/suggest.css @@ -69,8 +69,8 @@ margin-right: 0.3em; } -.monaco-workbench .workbench-suggest-widget.with-status-bar .monaco-list .monaco-list-row>.contents>.main>.right>.readMore, -.monaco-workbench .workbench-suggest-widget.with-status-bar .monaco-list .monaco-list-row.focused.string-label>.contents>.main>.right>.readMore { +.monaco-workbench .workbench-suggest-widget.with-status-bar .monaco-list .monaco-list-row > .contents > .main > .right > .readMore, +.monaco-workbench .workbench-suggest-widget.with-status-bar .monaco-list .monaco-list-row.focused.string-label > .contents > .main > .right > .readMore { display: none; } @@ -96,14 +96,14 @@ color: var(--vscode-editorSuggestWidget-selectedIconForeground); } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents { flex: 1; height: 100%; overflow: hidden; padding-left: 2px; } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main { display: flex; overflow: hidden; text-overflow: ellipsis; @@ -111,12 +111,12 @@ justify-content: space-between; } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left, -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left, +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right { display: flex; } -.workbench-suggest-widget .monaco-list .monaco-list-row:not(.focused)>.contents>.main .monaco-icon-label { +.workbench-suggest-widget .monaco-list .monaco-list-row:not(.focused) > .contents > .main .monaco-icon-label { color: var(--vscode-editorSuggestWidget-foreground); } @@ -124,11 +124,11 @@ font-weight: bold; } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main .monaco-highlighted-label .highlight { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main .monaco-highlighted-label .highlight { color: var(--vscode-editorSuggestWidget-highlightForeground); } -.workbench-suggest-widget .monaco-list .monaco-list-row.focused>.contents>.main .monaco-highlighted-label .highlight { +.workbench-suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main .monaco-highlighted-label .highlight { color: var(--vscode-editorSuggestWidget-focusHighlightForeground); } @@ -154,14 +154,14 @@ color: var(--vscode-editorSuggestWidget-selectedIconForeground); } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents { flex: 1; height: 100%; overflow: hidden; padding-left: 2px; } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main { display: flex; overflow: hidden; text-overflow: ellipsis; @@ -169,12 +169,12 @@ justify-content: space-between; } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left, -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left, +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right { display: flex; } -.workbench-suggest-widget .monaco-list .monaco-list-row:not(.focused)>.contents>.main .monaco-icon-label { +.workbench-suggest-widget .monaco-list .monaco-list-row:not(.focused) > .contents > .main .monaco-icon-label { color: var(--vscode-editorSuggestWidget-foreground); } @@ -182,11 +182,11 @@ font-weight: bold; } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main .monaco-highlighted-label .highlight { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main .monaco-highlighted-label .highlight { color: var(--vscode-editorSuggestWidget-highlightForeground); } -.workbench-suggest-widget .monaco-list .monaco-list-row.focused>.contents>.main .monaco-highlighted-label .highlight { +.workbench-suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main .monaco-highlighted-label .highlight { color: var(--vscode-editorSuggestWidget-focusHighlightForeground); } @@ -197,7 +197,7 @@ text-decoration: unset; } -.workbench-suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated>.monaco-icon-label-container>.monaco-icon-name-container { +.workbench-suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated > .monaco-icon-label-container > .monaco-icon-name-container { text-decoration: line-through; } @@ -239,17 +239,17 @@ } /** signature, qualifier, type/details opacity **/ -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label { opacity: 0.7; } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.signature-label { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .signature-label { overflow: hidden; text-overflow: ellipsis; opacity: 0.6; } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.qualifier-label { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .qualifier-label { margin-left: 12px; opacity: 0.4; font-size: 85%; @@ -261,7 +261,7 @@ /** Type Info and icon next to the label in the focused completion item **/ -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label { font-size: 85%; margin-left: 1.1em; overflow: hidden; @@ -269,59 +269,59 @@ white-space: nowrap; } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label>.monaco-tokenized-source { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label > .monaco-tokenized-source { display: inline; } /** Details: if using CompletionItem#details, show on focus **/ -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label { display: none; } -.workbench-suggest-widget:not(.shows-details) .monaco-list .monaco-list-row.focused>.contents>.main>.right>.details-label { +.workbench-suggest-widget:not(.shows-details) .monaco-list .monaco-list-row.focused > .contents > .main > .right > .details-label { display: inline; } /** Details: if using CompletionItemLabel#details, always show **/ -.workbench-suggest-widget .monaco-list .monaco-list-row:not(.string-label)>.contents>.main>.right>.details-label, -.workbench-suggest-widget.docs-side .monaco-list .monaco-list-row.focused:not(.string-label)>.contents>.main>.right>.details-label { +.workbench-suggest-widget .monaco-list .monaco-list-row:not(.string-label) > .contents > .main > .right > .details-label, +.workbench-suggest-widget.docs-side .monaco-list .monaco-list-row.focused:not(.string-label) > .contents > .main > .right > .details-label { display: inline; } /** Ellipsis on hover **/ -.workbench-suggest-widget:not(.docs-side) .monaco-list .monaco-list-row.focused:hover>.contents>.main>.right.can-expand-details>.details-label { +.workbench-suggest-widget:not(.docs-side) .monaco-list .monaco-list-row.focused:hover > .contents > .main > .right.can-expand-details > .details-label { width: calc(100% - 26px); } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left { flex-shrink: 1; flex-grow: 1; overflow: hidden; } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.monaco-icon-label { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .monaco-icon-label { flex-shrink: 0; } -.workbench-suggest-widget .monaco-list .monaco-list-row:not(.string-label)>.contents>.main>.left>.monaco-icon-label { +.workbench-suggest-widget .monaco-list .monaco-list-row:not(.string-label) > .contents > .main > .left > .monaco-icon-label { max-width: 100%; } -.workbench-suggest-widget .monaco-list .monaco-list-row.string-label>.contents>.main>.left>.monaco-icon-label { +.workbench-suggest-widget .monaco-list .monaco-list-row.string-label > .contents > .main > .left > .monaco-icon-label { flex-shrink: 1; } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right { overflow: hidden; flex-shrink: 4; max-width: 70%; } -.workbench-suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.readMore { +.workbench-suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .readMore { display: inline-block; position: absolute; right: 10px; diff --git a/src/vs/workbench/services/textMate/test/browser/arrayOperation.test.ts b/src/vs/workbench/services/textMate/test/browser/arrayOperation.test.ts index d51b85c57b6..917849e3b57 100644 --- a/src/vs/workbench/services/textMate/test/browser/arrayOperation.test.ts +++ b/src/vs/workbench/services/textMate/test/browser/arrayOperation.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { ArrayEdit, MonotonousIndexTransformer, SingleArrayEdit } from 'vs/workbench/services/textMate/browser/arrayOperation'; suite('array operation', () => { @@ -74,4 +75,6 @@ suite('array operation', () => { ] ); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 4ae7f6692c6..e546ab6c566 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -443,7 +443,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil try { const content = await this.textFileService.readStream(this.resource, { acceptTextOnly: !allowBinary, - etag, encoding: this.preferredEncoding, + etag, + encoding: this.preferredEncoding, limits: options?.limits }); diff --git a/src/vs/workbench/services/untitled/common/untitledTextEditorInput.ts b/src/vs/workbench/services/untitled/common/untitledTextEditorInput.ts index 5780d63cce9..766081132c1 100644 --- a/src/vs/workbench/services/untitled/common/untitledTextEditorInput.ts +++ b/src/vs/workbench/services/untitled/common/untitledTextEditorInput.ts @@ -19,6 +19,7 @@ import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { dispose, IReference } from 'vs/base/common/lifecycle'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration'; /** * An editor input to be used for untitled text buffers. @@ -47,9 +48,10 @@ export class UntitledTextEditorInput extends AbstractTextResourceEditorInput imp @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IPathService private readonly pathService: IPathService, @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService, - @ITextModelService private readonly textModelService: ITextModelService + @ITextModelService private readonly textModelService: ITextModelService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService ) { - super(model.resource, undefined, editorService, textFileService, labelService, fileService, filesConfigurationService); + super(model.resource, undefined, editorService, textFileService, labelService, fileService, filesConfigurationService, textResourceConfigurationService); this.registerModelListeners(model); } diff --git a/src/vs/workbench/services/userDataProfile/browser/media/userDataProfileView.css b/src/vs/workbench/services/userDataProfile/browser/media/userDataProfileView.css index ea08aa254b2..f5de028325f 100644 --- a/src/vs/workbench/services/userDataProfile/browser/media/userDataProfileView.css +++ b/src/vs/workbench/services/userDataProfile/browser/media/userDataProfileView.css @@ -7,43 +7,43 @@ display: inherit; } -.monaco-workbench .pane>.pane-body>.profile-view-message-container { +.monaco-workbench .pane > .pane-body > .profile-view-message-container { display: flex; padding: 13px 20px 0px 20px; box-sizing: border-box; } -.monaco-workbench .pane>.pane-body>.profile-view-message-container p { +.monaco-workbench .pane > .pane-body > .profile-view-message-container p { margin-block-start: 0em; margin-block-end: 0em; } -.monaco-workbench .pane>.pane-body>.profile-view-message-container a { +.monaco-workbench .pane > .pane-body > .profile-view-message-container a { color: var(--vscode-textLink-foreground) } -.monaco-workbench .pane>.pane-body>.profile-view-message-container a:hover { +.monaco-workbench .pane > .pane-body > .profile-view-message-container a:hover { text-decoration: underline; color: var(--vscode-textLink-activeForeground) } -.monaco-workbench .pane>.pane-body>.profile-view-message-container a:active { +.monaco-workbench .pane > .pane-body > .profile-view-message-container a:active { color: var(--vscode-textLink-activeForeground) } -.monaco-workbench .pane>.pane-body>.profile-view-message-container.hide { +.monaco-workbench .pane > .pane-body > .profile-view-message-container.hide { display: none; } -.monaco-workbench .pane>.pane-body>.profile-view-buttons-container { +.monaco-workbench .pane > .pane-body > .profile-view-buttons-container { display: flex; flex-direction: column; padding: 13px 20px; box-sizing: border-box; } -.monaco-workbench .pane>.pane-body>.profile-view-buttons-container>.monaco-button, -.monaco-workbench .pane>.pane-body>.profile-view-buttons-container>.monaco-button-dropdown { +.monaco-workbench .pane > .pane-body > .profile-view-buttons-container > .monaco-button, +.monaco-workbench .pane > .pane-body > .profile-view-buttons-container > .monaco-button-dropdown { margin-block-start: 13px; margin-inline-start: 0px; margin-inline-end: 0px; @@ -52,11 +52,11 @@ margin-right: auto; } -.monaco-workbench .pane>.pane-body>.profile-view-buttons-container>.monaco-button-dropdown { +.monaco-workbench .pane > .pane-body > .profile-view-buttons-container > .monaco-button-dropdown { width: 100%; } -.monaco-workbench .pane>.pane-body>.profile-view-buttons-container>.monaco-button-dropdown>.monaco-dropdown-button { +.monaco-workbench .pane > .pane-body > .profile-view-buttons-container > .monaco-button-dropdown > .monaco-dropdown-button { display: flex; align-items: center; padding: 0 4px; diff --git a/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopy.ts b/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopy.ts index 7a00e3208d8..aee59bce62b 100644 --- a/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopy.ts +++ b/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopy.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; -import { ETAG_DISABLED, FileOperationError, FileOperationResult, IFileService, IFileStatWithMetadata, IFileStreamContent, IWriteFileOptions, NotModifiedSinceFileOperationError } from 'vs/platform/files/common/files'; +import { ETAG_DISABLED, FileOperationError, FileOperationResult, IFileReadLimits, IFileService, IFileStatWithMetadata, IFileStreamContent, IWriteFileOptions, NotModifiedSinceFileOperationError } from 'vs/platform/files/common/files'; import { ISaveOptions, IRevertOptions, SaveReason } from 'vs/workbench/common/editor'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { IWorkingCopyBackup, IWorkingCopyBackupMeta, IWorkingCopySaveEvent, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopy'; @@ -262,6 +262,12 @@ export interface IStoredFileWorkingCopyResolveOptions { * Go to disk bypassing any cache of the stored file working copy if any. */ readonly forceReadFromFile?: boolean; + + /** + * If provided, the size of the file will be checked against the limits + * and an error will be thrown if any limit is exceeded. + */ + readonly limits?: IFileReadLimits; } /** @@ -571,7 +577,10 @@ export class StoredFileWorkingCopy extend // Resolve Content try { - const content = await this.fileService.readFileStream(this.resource, { etag }); + const content = await this.fileService.readFileStream(this.resource, { + etag, + limits: options?.limits + }); // Clear orphaned state when resolving was successful this.setOrphaned(false); diff --git a/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopyManager.ts b/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopyManager.ts index cfdce4134e3..f76fdd404c7 100644 --- a/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopyManager.ts +++ b/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopyManager.ts @@ -475,7 +475,8 @@ export class StoredFileWorkingCopyManager const resolveOptions: IStoredFileWorkingCopyResolveOptions = { contents: options?.contents, - forceReadFromFile: options?.reload?.force + forceReadFromFile: options?.reload?.force, + limits: options?.limits }; // Working copy exists diff --git a/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts b/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts index 4653e395be9..21312c7e76c 100644 --- a/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts +++ b/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts @@ -37,7 +37,7 @@ export abstract class AbstractWorkspaceEditingService implements IWorkspaceEditi constructor( @IJSONEditingService private readonly jsonEditingService: IJSONEditingService, @IWorkspaceContextService protected readonly contextService: WorkspaceService, - @IWorkbenchConfigurationService private readonly configurationService: IWorkbenchConfigurationService, + @IWorkbenchConfigurationService protected readonly configurationService: IWorkbenchConfigurationService, @INotificationService private readonly notificationService: INotificationService, @ICommandService private readonly commandService: ICommandService, @IFileService private readonly fileService: IFileService, diff --git a/src/vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService.ts b/src/vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService.ts index ad00669d146..63dd1b18ad3 100644 --- a/src/vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService.ts @@ -33,6 +33,7 @@ import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/w import { IWorkbenchConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export class NativeWorkspaceEditingService extends AbstractWorkspaceEditingService { @@ -87,7 +88,13 @@ export class NativeWorkspaceEditingService extends AbstractWorkspaceEditingServi return false; // Windows/Linux: quits when last window is closed, so do not ask then } - const { result } = await this.dialogService.prompt({ + const confirmSaveUntitledWorkspace = this.configurationService.getValue('window.confirmSaveUntitledWorkspace') !== false; + if (!confirmSaveUntitledWorkspace) { + return false; // no confirmation configured + } + + let canceled = false; + const { result, checkboxChecked } = await this.dialogService.prompt({ type: Severity.Warning, message: localize('saveWorkspaceMessage', "Do you want to save your workspace configuration as a file?"), detail: localize('saveWorkspaceDetail', "Save your workspace if you plan to open it again."), @@ -130,10 +137,21 @@ export class NativeWorkspaceEditingService extends AbstractWorkspaceEditingServi } ], cancelButton: { - run: () => true // veto + run: () => { + canceled = true; + + return true; // veto + } + }, + checkbox: { + label: localize('doNotAskAgain', "Do not ask me again") } }); + if (!canceled && checkboxChecked) { + await this.configurationService.updateValue('window.confirmSaveUntitledWorkspace', false, ConfigurationTarget.USER); + } + return result; } diff --git a/src/vs/workbench/test/browser/parts/editor/resourceEditorInput.test.ts b/src/vs/workbench/test/browser/parts/editor/resourceEditorInput.test.ts index f44f395fac6..7481879807d 100644 --- a/src/vs/workbench/test/browser/parts/editor/resourceEditorInput.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/resourceEditorInput.test.ts @@ -14,6 +14,7 @@ import { EditorInputCapabilities, Verbosity } from 'vs/workbench/common/editor'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration'; suite('ResourceEditorInput', () => { @@ -28,9 +29,10 @@ suite('ResourceEditorInput', () => { resource: URI, @ILabelService labelService: ILabelService, @IFileService fileService: IFileService, - @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService ) { - super(resource, resource, labelService, fileService, filesConfigurationService); + super(resource, resource, labelService, fileService, filesConfigurationService, textResourceConfigurationService); } } diff --git a/src/vs/workbench/test/browser/webview.test.ts b/src/vs/workbench/test/browser/webview.test.ts index 484be00a657..3d0c3701f14 100644 --- a/src/vs/workbench/test/browser/webview.test.ts +++ b/src/vs/workbench/test/browser/webview.test.ts @@ -5,6 +5,7 @@ import * as assert from 'assert'; import { parentOriginHash } from 'vs/base/browser/iframe'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; suite('parentOriginHash', () => { @@ -22,4 +23,6 @@ suite('parentOriginHash', () => { const hash = await parentOriginHash('http://localhost:9887', '123456'); assert.strictEqual(hash, '1v1128i162q0nee9l89360sqan26u3pdnjrkke5ijd0sel8sbtqf'); }); + + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/test/unit/electron/index.js b/test/unit/electron/index.js index 81c5752111d..a02bce4999c 100644 --- a/test/unit/electron/index.js +++ b/test/unit/electron/index.js @@ -43,8 +43,8 @@ const minimist = require('minimist'); * }} */ const args = minimist(process.argv.slice(2), { - string: ['grep', 'run', 'runGlob', 'dev', 'reporter', 'reporter-options', 'wait-server', 'timeout', 'crash-reporter-directory', 'tfs'], - boolean: ['build', 'coverage', 'help'], + string: ['grep', 'run', 'runGlob', 'reporter', 'reporter-options', 'wait-server', 'timeout', 'crash-reporter-directory', 'tfs'], + boolean: ['build', 'coverage', 'help', 'dev'], alias: { 'grep': ['g', 'f'], 'runGlob': ['glob', 'runGrep'],