Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/microsoft/vscode.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes <johannes.rieken@gmail.com>2022-06-09 10:08:20 +0300
committerJohannes <johannes.rieken@gmail.com>2022-06-09 10:08:20 +0300
commit3622010b64abbdf8bab57bc0d163f74fe10f3787 (patch)
treeed5a642f53143ce35a7cc2e2fab9fcd4f490953f
parentb501e6296339a7d8338c13a85f8928fa264fc961 (diff)
parent54ae4d8ccbf4574889c24b086079a745b3debf96 (diff)
Merge branch 'main' into joh/voluminous-lobster
-rw-r--r--.github/workflows/pr-chat.yml1
-rw-r--r--.vscode/launch.json7
-rw-r--r--.vscode/notebooks/api.github-issues2
-rw-r--r--.vscode/notebooks/my-work.github-issues2
-rw-r--r--build/lib/extensions.ts2
-rw-r--r--extensions/git/extension.webpack.config.js3
-rw-r--r--extensions/git/package.json61
-rw-r--r--extensions/git/package.nls.json2
-rw-r--r--extensions/git/src/api/git.d.ts3
-rw-r--r--extensions/git/src/askpass.ts14
-rw-r--r--extensions/git/src/commands.ts39
-rwxr-xr-xextensions/git/src/git-editor-empty.sh1
-rw-r--r--extensions/git/src/git-editor-main.ts21
-rwxr-xr-xextensions/git/src/git-editor.sh4
-rw-r--r--extensions/git/src/git.ts34
-rw-r--r--extensions/git/src/gitEditor.ts65
-rw-r--r--extensions/git/src/main.ts17
-rw-r--r--extensions/git/src/repository.ts7
-rw-r--r--extensions/git/tsconfig.json1
-rw-r--r--extensions/markdown-language-features/src/languageFeatures/copyPaste.ts14
-rw-r--r--extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts15
-rw-r--r--extensions/markdown-language-features/src/languageFeatures/rename.ts2
-rw-r--r--extensions/markdown-language-features/src/test/rename.test.ts75
-rw-r--r--extensions/npm/src/tasks.ts9
-rw-r--r--extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json2
-rw-r--r--extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts1
-rw-r--r--extensions/vscode-api-tests/src/singlefolder-tests/ipynb.test.ts8
-rw-r--r--extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts8
-rw-r--r--extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts108
-rw-r--r--package.json2
-rw-r--r--src/vs/editor/common/languages.ts29
-rw-r--r--src/vs/editor/contrib/copyPaste/browser/copyPasteController.ts55
-rw-r--r--src/vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution.ts31
-rw-r--r--src/vs/editor/contrib/snippet/browser/snippetController2.ts9
-rw-r--r--src/vs/monaco.d.ts5
-rw-r--r--src/vs/platform/remote/browser/remoteAuthorityResolverService.ts11
-rw-r--r--src/vs/platform/remote/common/remoteHosts.ts43
-rw-r--r--src/vs/platform/remote/test/common/remoteHosts.test.ts38
-rw-r--r--src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts37
-rw-r--r--src/vs/workbench/api/common/extHost.api.impl.ts5
-rw-r--r--src/vs/workbench/api/common/extHost.protocol.ts18
-rw-r--r--src/vs/workbench/api/common/extHostLanguageFeatures.ts45
-rw-r--r--src/vs/workbench/api/common/extHostTypeConverters.ts9
-rw-r--r--src/vs/workbench/api/common/extHostTypes.ts11
-rw-r--r--src/vs/workbench/browser/parts/editor/editor.contribution.ts31
-rw-r--r--src/vs/workbench/browser/parts/editor/editorActions.ts69
-rw-r--r--src/vs/workbench/browser/parts/editor/editorDropTarget.ts1
-rw-r--r--src/vs/workbench/contrib/debug/browser/debugService.ts7
-rw-r--r--src/vs/workbench/contrib/debug/browser/variablesView.ts4
-rw-r--r--src/vs/workbench/contrib/debug/common/debugModel.ts20
-rw-r--r--src/vs/workbench/contrib/extensions/browser/extensionEditor.ts111
-rw-r--r--src/vs/workbench/contrib/extensions/browser/extensionsActions.ts3
-rw-r--r--src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts96
-rw-r--r--src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css27
-rw-r--r--src/vs/workbench/contrib/extensions/common/extensions.ts4
-rw-r--r--src/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts4
-rw-r--r--src/vs/workbench/contrib/localization/browser/localeService.ts3
-rw-r--r--src/vs/workbench/contrib/localization/browser/localization.contribution.ts5
-rw-r--r--src/vs/workbench/contrib/localization/browser/localizationsActions.ts4
-rw-r--r--src/vs/workbench/contrib/localization/electron-sandbox/localeService.ts24
-rw-r--r--src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts5
-rw-r--r--src/vs/workbench/contrib/mergeEditor/browser/editorGutter.ts2
-rw-r--r--src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts8
-rw-r--r--src/vs/workbench/contrib/notebook/browser/extensionPoint.ts29
-rw-r--r--src/vs/workbench/contrib/notebook/common/notebookCommon.ts2
-rw-r--r--src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css10
-rw-r--r--src/vs/workbench/contrib/scm/browser/util.ts2
-rw-r--r--src/vs/workbench/contrib/tasks/common/taskConfiguration.ts2
-rw-r--r--src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh8
-rw-r--r--src/vs/workbench/contrib/terminal/browser/terminalService.ts10
-rw-r--r--src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts7
-rw-r--r--src/vs/workbench/services/decorations/browser/decorationsService.ts3
-rw-r--r--src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts8
-rw-r--r--src/vs/workbench/workbench.sandbox.main.ts1
-rw-r--r--src/vs/workbench/workbench.web.main.ts1
-rw-r--r--src/vscode-dts/vscode.proposed.documentPaste.d.ts34
-rw-r--r--src/vscode-dts/vscode.proposed.textEditorDrop.d.ts25
-rw-r--r--yarn.lock8
78 files changed, 970 insertions, 484 deletions
diff --git a/.github/workflows/pr-chat.yml b/.github/workflows/pr-chat.yml
index 13803fda778..da4538d5fd1 100644
--- a/.github/workflows/pr-chat.yml
+++ b/.github/workflows/pr-chat.yml
@@ -21,5 +21,6 @@ jobs:
with:
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
slack_token: ${{ secrets.SLACK_TOKEN }}
+ slack_user_token: ${{ secrets.SLACK_USER_TOKEN }}
slack_bot_name: "VSCodeBot"
notification_channel: codereview
diff --git a/.vscode/launch.json b/.vscode/launch.json
index dd295c02db4..236fc3de8c3 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -16,11 +16,7 @@
"request": "attach",
"restart": true,
"name": "Attach to Extension Host",
- // set to a large number: if there is an issue we're debugging that keeps
- // the extension host from coming up, or the renderer is paused/crashes
- // before it happens, developers will get an annoying alert, e.g. #126826.
- // This can be set to 0 in 1.59.
- "timeout": 999999999,
+ "timeout": 0,
"port": 5870,
"outFiles": [
"${workspaceFolder}/out/**/*.js",
@@ -244,6 +240,7 @@
"runtimeArgs": [
"--inspect=5875",
"--no-cached-data",
+ "--crash-reporter-directory=${workspaceFolder}/.profile-oss/crashes",
// for general runtime freezes: https://github.com/microsoft/vscode/issues/127861#issuecomment-904144910
"--disable-features=CalculateNativeWinOcclusion",
],
diff --git a/.vscode/notebooks/api.github-issues b/.vscode/notebooks/api.github-issues
index 1b3790c8cc9..3120d4ad8fc 100644
--- a/.vscode/notebooks/api.github-issues
+++ b/.vscode/notebooks/api.github-issues
@@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
- "value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"May 2022\""
+ "value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"June 2022\""
},
{
"kind": 1,
diff --git a/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues
index 143697b0c4e..f596c6e2e1c 100644
--- a/.vscode/notebooks/my-work.github-issues
+++ b/.vscode/notebooks/my-work.github-issues
@@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
- "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce\n\n// current milestone name\n$milestone=milestone:\"May 2022\""
+ "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce\n\n// current milestone name\n$milestone=milestone:\"June 2022\""
},
{
"kind": 1,
diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts
index 4aaf668a6c4..271b25ad228 100644
--- a/build/lib/extensions.ts
+++ b/build/lib/extensions.ts
@@ -500,7 +500,7 @@ export async function webpackExtensions(taskName: string, isWatch: boolean, webp
function addConfig(configOrFn: webpack.Configuration | Function) {
let config;
if (typeof configOrFn === 'function') {
- config = configOrFn({}, {});
+ config = (configOrFn as Function)({}, {});
webpackConfigs.push(config);
} else {
config = configOrFn;
diff --git a/extensions/git/extension.webpack.config.js b/extensions/git/extension.webpack.config.js
index 5efa2052e88..3324b6c1d98 100644
--- a/extensions/git/extension.webpack.config.js
+++ b/extensions/git/extension.webpack.config.js
@@ -13,6 +13,7 @@ module.exports = withDefaults({
context: __dirname,
entry: {
main: './src/main.ts',
- ['askpass-main']: './src/askpass-main.ts'
+ ['askpass-main']: './src/askpass-main.ts',
+ ['git-editor-main']: './src/git-editor-main.ts'
}
});
diff --git a/extensions/git/package.json b/extensions/git/package.json
index e2428b5e02f..111717f86c9 100644
--- a/extensions/git/package.json
+++ b/extensions/git/package.json
@@ -14,6 +14,7 @@
"contribMergeEditorToolbar",
"contribViewsWelcome",
"scmActionButton",
+ "scmInput",
"scmSelectedProvider",
"scmValidation",
"timeline"
@@ -213,83 +214,99 @@
"command": "git.commit",
"title": "%command.commit%",
"category": "Git",
- "icon": "$(check)"
+ "icon": "$(check)",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitStaged",
"title": "%command.commitStaged%",
- "category": "Git"
+ "category": "Git",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitEmpty",
"title": "%command.commitEmpty%",
- "category": "Git"
+ "category": "Git",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitStagedSigned",
"title": "%command.commitStagedSigned%",
- "category": "Git"
+ "category": "Git",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitStagedAmend",
"title": "%command.commitStagedAmend%",
- "category": "Git"
+ "category": "Git",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitAll",
"title": "%command.commitAll%",
- "category": "Git"
+ "category": "Git",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitAllSigned",
"title": "%command.commitAllSigned%",
- "category": "Git"
+ "category": "Git",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitAllAmend",
"title": "%command.commitAllAmend%",
- "category": "Git"
+ "category": "Git",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitNoVerify",
"title": "%command.commitNoVerify%",
"category": "Git",
- "icon": "$(check)"
+ "icon": "$(check)",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitStagedNoVerify",
"title": "%command.commitStagedNoVerify%",
- "category": "Git"
+ "category": "Git",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitEmptyNoVerify",
"title": "%command.commitEmptyNoVerify%",
- "category": "Git"
+ "category": "Git",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitStagedSignedNoVerify",
"title": "%command.commitStagedSignedNoVerify%",
- "category": "Git"
+ "category": "Git",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitStagedAmendNoVerify",
"title": "%command.commitStagedAmendNoVerify%",
- "category": "Git"
+ "category": "Git",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitAllNoVerify",
"title": "%command.commitAllNoVerify%",
- "category": "Git"
+ "category": "Git",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitAllSignedNoVerify",
"title": "%command.commitAllSignedNoVerify%",
- "category": "Git"
+ "category": "Git",
+ "enablement": "!commitInProgress"
},
{
"command": "git.commitAllAmendNoVerify",
"title": "%command.commitAllAmendNoVerify%",
- "category": "Git"
+ "category": "Git",
+ "enablement": "!commitInProgress"
},
{
"command": "git.restoreCommitTemplate",
@@ -2013,6 +2030,18 @@
"scope": "machine",
"description": "%config.defaultCloneDirectory%"
},
+ "git.useEditorAsCommitInput": {
+ "type": "boolean",
+ "scope": "resource",
+ "description": "%config.useEditorAsCommitInput%",
+ "default": false
+ },
+ "git.verboseCommit": {
+ "type": "boolean",
+ "scope": "resource",
+ "markdownDescription": "%config.verboseCommit%",
+ "default": false
+ },
"git.enableSmartCommit": {
"type": "boolean",
"scope": "resource",
diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json
index b729f821b61..5210e64de80 100644
--- a/extensions/git/package.nls.json
+++ b/extensions/git/package.nls.json
@@ -140,6 +140,8 @@
"config.ignoreLimitWarning": "Ignores the warning when there are too many changes in a repository.",
"config.ignoreRebaseWarning": "Ignores the warning when it looks like the branch might have been rebased when pulling.",
"config.defaultCloneDirectory": "The default location to clone a git repository.",
+ "config.useEditorAsCommitInput": "Use an editor to author the commit message.",
+ "config.verboseCommit": "Enable verbose output when `#git.useEditorAsCommitInput#` is enabled.",
"config.enableSmartCommit": "Commit all changes when there are no staged changes.",
"config.smartCommitChanges": "Control which changes are automatically staged by Smart Commit.",
"config.smartCommitChanges.all": "Automatically stage all changes.",
diff --git a/extensions/git/src/api/git.d.ts b/extensions/git/src/api/git.d.ts
index 4b180dac920..14c7447e3e8 100644
--- a/extensions/git/src/api/git.d.ts
+++ b/extensions/git/src/api/git.d.ts
@@ -137,6 +137,8 @@ export interface CommitOptions {
empty?: boolean;
noVerify?: boolean;
requireUserConfig?: boolean;
+ useEditor?: boolean;
+ verbose?: boolean;
}
export interface FetchOptions {
@@ -336,4 +338,5 @@ export const enum GitErrorCodes {
PatchDoesNotApply = 'PatchDoesNotApply',
NoPathFound = 'NoPathFound',
UnknownPath = 'UnknownPath',
+ EmptyCommitMessage = 'EmptyCommitMessage'
}
diff --git a/extensions/git/src/askpass.ts b/extensions/git/src/askpass.ts
index 2f9678c6e04..d9d9378f8aa 100644
--- a/extensions/git/src/askpass.ts
+++ b/extensions/git/src/askpass.ts
@@ -6,9 +6,8 @@
import { window, InputBoxOptions, Uri, Disposable, workspace } from 'vscode';
import { IDisposable, EmptyDisposable, toDisposable } from './util';
import * as path from 'path';
-import { IIPCHandler, IIPCServer, createIPCServer } from './ipc/ipcServer';
+import { IIPCHandler, IIPCServer } from './ipc/ipcServer';
import { CredentialsProvider, Credentials } from './api/git';
-import { OutputChannelLogger } from './log';
export class Askpass implements IIPCHandler {
@@ -16,16 +15,7 @@ export class Askpass implements IIPCHandler {
private cache = new Map<string, Credentials>();
private credentialsProviders = new Set<CredentialsProvider>();
- static async create(outputChannelLogger: OutputChannelLogger, context?: string): Promise<Askpass> {
- try {
- return new Askpass(await createIPCServer(context));
- } catch (err) {
- outputChannelLogger.logError(`Failed to create git askpass IPC: ${err}`);
- return new Askpass();
- }
- }
-
- private constructor(private ipc?: IIPCServer) {
+ constructor(private ipc?: IIPCServer) {
if (ipc) {
this.disposable = ipc.registerHandler('askpass', this);
}
diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts
index cd43dc2ea6e..e3968df3a0d 100644
--- a/extensions/git/src/commands.ts
+++ b/extensions/git/src/commands.ts
@@ -1516,6 +1516,14 @@ export class CommandCenter {
opts.signoff = true;
}
+ if (config.get<boolean>('useEditorAsCommitInput')) {
+ opts.useEditor = true;
+
+ if (config.get<boolean>('verboseCommit')) {
+ opts.verbose = true;
+ }
+ }
+
const smartCommitChanges = config.get<'all' | 'tracked'>('smartCommitChanges');
if (
@@ -1563,7 +1571,7 @@ export class CommandCenter {
const message = await getCommitMessage();
- if (!message && !opts.amend) {
+ if (!message && !opts.amend && !opts.useEditor) {
return false;
}
@@ -1623,10 +1631,13 @@ export class CommandCenter {
private async commitWithAnyInput(repository: Repository, opts?: CommitOptions): Promise<void> {
const message = repository.inputBox.value;
+ const root = Uri.file(repository.root);
+ const config = workspace.getConfiguration('git', root);
+
const getCommitMessage = async () => {
let _message: string | undefined = message;
- if (!_message) {
+ if (!_message && !config.get<boolean>('useEditorAsCommitInput')) {
const value: string | undefined = undefined;
if (opts && opts.amend && repository.HEAD && repository.HEAD.commit) {
@@ -3010,7 +3021,7 @@ export class CommandCenter {
};
let message: string;
- let type: 'error' | 'warning' = 'error';
+ let type: 'error' | 'warning' | 'information' = 'error';
const choices = new Map<string, () => void>();
const openOutputChannelChoice = localize('open git log', "Open Git Log");
@@ -3073,6 +3084,12 @@ export class CommandCenter {
message = localize('missing user info', "Make sure you configure your 'user.name' and 'user.email' in git.");
choices.set(localize('learn more', "Learn More"), () => commands.executeCommand('vscode.open', Uri.parse('https://aka.ms/vscode-setup-git')));
break;
+ case GitErrorCodes.EmptyCommitMessage:
+ message = localize('empty commit', "Commit operation was cancelled due to empty commit message.");
+ choices.clear();
+ type = 'information';
+ options.modal = false;
+ break;
default: {
const hint = (err.stderr || err.message || String(err))
.replace(/^error: /mi, '')
@@ -3094,10 +3111,20 @@ export class CommandCenter {
return;
}
+ let result: string | undefined;
const allChoices = Array.from(choices.keys());
- const result = type === 'error'
- ? await window.showErrorMessage(message, options, ...allChoices)
- : await window.showWarningMessage(message, options, ...allChoices);
+
+ switch (type) {
+ case 'error':
+ result = await window.showErrorMessage(message, options, ...allChoices);
+ break;
+ case 'warning':
+ result = await window.showWarningMessage(message, options, ...allChoices);
+ break;
+ case 'information':
+ result = await window.showInformationMessage(message, options, ...allChoices);
+ break;
+ }
if (result) {
const resultFn = choices.get(result);
diff --git a/extensions/git/src/git-editor-empty.sh b/extensions/git/src/git-editor-empty.sh
new file mode 100755
index 00000000000..1a2485251c3
--- /dev/null
+++ b/extensions/git/src/git-editor-empty.sh
@@ -0,0 +1 @@
+#!/bin/sh
diff --git a/extensions/git/src/git-editor-main.ts b/extensions/git/src/git-editor-main.ts
new file mode 100644
index 00000000000..eb4da4a40b5
--- /dev/null
+++ b/extensions/git/src/git-editor-main.ts
@@ -0,0 +1,21 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+import { IPCClient } from './ipc/ipcClient';
+
+function fatal(err: any): void {
+ console.error(err);
+ process.exit(1);
+}
+
+function main(argv: string[]): void {
+ const ipcClient = new IPCClient('git-editor');
+ const commitMessagePath = argv[argv.length - 1];
+
+ ipcClient.call({ commitMessagePath }).then(() => {
+ setTimeout(() => process.exit(0), 0);
+ }).catch(err => fatal(err));
+}
+
+main(process.argv);
diff --git a/extensions/git/src/git-editor.sh b/extensions/git/src/git-editor.sh
new file mode 100755
index 00000000000..1c45c2deac1
--- /dev/null
+++ b/extensions/git/src/git-editor.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+ELECTRON_RUN_AS_NODE="1" \
+"$VSCODE_GIT_EDITOR_NODE" "$VSCODE_GIT_EDITOR_MAIN" $VSCODE_GIT_EDITOR_EXTRA_ARGS $@
diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts
index 203d6949897..5e7ddef8599 100644
--- a/extensions/git/src/git.ts
+++ b/extensions/git/src/git.ts
@@ -1400,20 +1400,37 @@ export class Repository {
}
async commit(message: string | undefined, opts: CommitOptions = Object.create(null)): Promise<void> {
- const args = ['commit', '--quiet', '--allow-empty-message'];
+ const args = ['commit', '--quiet'];
+ const options: SpawnOptions = {};
+
+ if (message) {
+ options.input = message;
+ args.push('--file', '-');
+ }
+
+ if (opts.verbose) {
+ args.push('--verbose');
+ }
if (opts.all) {
args.push('--all');
}
- if (opts.amend && message) {
+ if (opts.amend) {
args.push('--amend');
}
- if (opts.amend && !message) {
- args.push('--amend', '--no-edit');
- } else {
- args.push('--file', '-');
+ if (!opts.useEditor) {
+ if (!message) {
+ if (opts.amend) {
+ args.push('--no-edit');
+ } else {
+ options.input = '';
+ args.push('--file', '-');
+ }
+ }
+
+ args.push('--allow-empty-message');
}
if (opts.signoff) {
@@ -1438,7 +1455,7 @@ export class Repository {
}
try {
- await this.exec(args, !opts.amend || message ? { input: message || '' } : {});
+ await this.exec(args, options);
} catch (commitErr) {
await this.handleCommitError(commitErr);
}
@@ -1462,6 +1479,9 @@ export class Repository {
if (/not possible because you have unmerged files/.test(commitErr.stderr || '')) {
commitErr.gitErrorCode = GitErrorCodes.UnmergedChanges;
throw commitErr;
+ } else if (/Aborting commit due to empty commit message/.test(commitErr.stderr || '')) {
+ commitErr.gitErrorCode = GitErrorCodes.EmptyCommitMessage;
+ throw commitErr;
}
try {
diff --git a/extensions/git/src/gitEditor.ts b/extensions/git/src/gitEditor.ts
new file mode 100644
index 00000000000..5f65a7dbcf2
--- /dev/null
+++ b/extensions/git/src/gitEditor.ts
@@ -0,0 +1,65 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+import * as path from 'path';
+import { TabInputText, Uri, window, workspace } from 'vscode';
+import { IIPCHandler, IIPCServer } from './ipc/ipcServer';
+import { EmptyDisposable, IDisposable } from './util';
+
+interface GitEditorRequest {
+ commitMessagePath?: string;
+}
+
+export class GitEditor implements IIPCHandler {
+
+ private disposable: IDisposable = EmptyDisposable;
+
+ constructor(private ipc?: IIPCServer) {
+ if (ipc) {
+ this.disposable = ipc.registerHandler('git-editor', this);
+ }
+ }
+
+ async handle({ commitMessagePath }: GitEditorRequest): Promise<any> {
+ if (commitMessagePath) {
+ const uri = Uri.file(commitMessagePath);
+ const doc = await workspace.openTextDocument(uri);
+ await window.showTextDocument(doc, { preview: false });
+
+ return new Promise((c) => {
+ const onDidClose = window.tabGroups.onDidChangeTabs(async (tabs) => {
+ if (tabs.closed.some(t => t.input instanceof TabInputText && t.input.uri.toString() === uri.toString())) {
+ onDidClose.dispose();
+ return c(true);
+ }
+ });
+ });
+ }
+ }
+
+ getEnv(): { [key: string]: string } {
+ if (!this.ipc) {
+ return {
+ GIT_EDITOR: `"${path.join(__dirname, 'git-editor-empty.sh')}"`
+ };
+ }
+
+ let env: { [key: string]: string } = {
+ VSCODE_GIT_EDITOR_NODE: process.execPath,
+ VSCODE_GIT_EDITOR_EXTRA_ARGS: (process.versions['electron'] && process.versions['microsoft-build']) ? '--ms-enable-electron-run-as-node' : '',
+ VSCODE_GIT_EDITOR_MAIN: path.join(__dirname, 'git-editor-main.js')
+ };
+
+ const config = workspace.getConfiguration('git');
+ if (config.get<boolean>('useEditorAsCommitInput')) {
+ env.GIT_EDITOR = `"${path.join(__dirname, 'git-editor.sh')}"`;
+ }
+
+ return env;
+ }
+
+ dispose(): void {
+ this.disposable.dispose();
+ }
+}
diff --git a/extensions/git/src/main.ts b/extensions/git/src/main.ts
index a5e7c060f00..46f612539fb 100644
--- a/extensions/git/src/main.ts
+++ b/extensions/git/src/main.ts
@@ -25,6 +25,8 @@ import { GitTimelineProvider } from './timelineProvider';
import { registerAPICommands } from './api/api1';
import { TerminalEnvironmentManager } from './terminal';
import { OutputChannelLogger } from './log';
+import { createIPCServer, IIPCServer } from './ipc/ipcServer';
+import { GitEditor } from './gitEditor';
const deactivateTasks: { (): Promise<any> }[] = [];
@@ -60,10 +62,21 @@ async function createModel(context: ExtensionContext, outputChannelLogger: Outpu
return !skip;
});
- const askpass = await Askpass.create(outputChannelLogger, context.storagePath);
+ let ipc: IIPCServer | undefined = undefined;
+
+ try {
+ ipc = await createIPCServer(context.storagePath);
+ } catch (err) {
+ outputChannelLogger.logError(`Failed to create git IPC: ${err}`);
+ }
+
+ const askpass = new Askpass(ipc);
disposables.push(askpass);
- const environment = askpass.getEnv();
+ const gitEditor = new GitEditor(ipc);
+ disposables.push(gitEditor);
+
+ const environment = { ...askpass.getEnv(), ...gitEditor.getEnv() };
const terminalEnvironmentManager = new TerminalEnvironmentManager(context, environment);
disposables.push(terminalEnvironmentManager);
diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts
index 69c184209fa..c6fa51b5497 100644
--- a/extensions/git/src/repository.ts
+++ b/extensions/git/src/repository.ts
@@ -454,6 +454,13 @@ class ProgressManager {
const onDidChange = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git', Uri.file(this.repository.root)));
onDidChange(_ => this.updateEnablement());
this.updateEnablement();
+
+ this.repository.onDidChangeOperations(() => {
+ const commitInProgress = this.repository.operations.isRunning(Operation.Commit);
+
+ this.repository.sourceControl.inputBox.enabled = !commitInProgress;
+ commands.executeCommand('setContext', 'commitInProgress', commitInProgress);
+ });
}
private updateEnablement(): void {
diff --git a/extensions/git/tsconfig.json b/extensions/git/tsconfig.json
index 13997275056..1f1c02d3356 100644
--- a/extensions/git/tsconfig.json
+++ b/extensions/git/tsconfig.json
@@ -12,6 +12,7 @@
"../../src/vscode-dts/vscode.d.ts",
"../../src/vscode-dts/vscode.proposed.diffCommand.d.ts",
"../../src/vscode-dts/vscode.proposed.scmActionButton.d.ts",
+ "../../src/vscode-dts/vscode.proposed.scmInput.d.ts",
"../../src/vscode-dts/vscode.proposed.scmSelectedProvider.d.ts",
"../../src/vscode-dts/vscode.proposed.scmValidation.d.ts",
"../../src/vscode-dts/vscode.proposed.tabs.d.ts",
diff --git a/extensions/markdown-language-features/src/languageFeatures/copyPaste.ts b/extensions/markdown-language-features/src/languageFeatures/copyPaste.ts
index d9e939b463c..c36403d06ee 100644
--- a/extensions/markdown-language-features/src/languageFeatures/copyPaste.ts
+++ b/extensions/markdown-language-features/src/languageFeatures/copyPaste.ts
@@ -4,23 +4,29 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
-import { tryInsertUriList } from './dropIntoEditor';
+import { tryGetUriListSnippet } from './dropIntoEditor';
export function registerPasteProvider(selector: vscode.DocumentSelector) {
return vscode.languages.registerDocumentPasteEditProvider(selector, new class implements vscode.DocumentPasteEditProvider {
async provideDocumentPasteEdits(
document: vscode.TextDocument,
- range: vscode.Range,
+ _ranges: readonly vscode.Range[],
dataTransfer: vscode.DataTransfer,
token: vscode.CancellationToken,
- ): Promise<vscode.SnippetTextEdit | undefined> {
+ ): Promise<vscode.DocumentPasteEdit | undefined> {
const enabled = vscode.workspace.getConfiguration('markdown', document).get('experimental.editor.pasteLinks.enabled', false);
if (!enabled) {
return;
}
- return tryInsertUriList(document, range, dataTransfer, token);
+ const snippet = await tryGetUriListSnippet(document, dataTransfer, token);
+ if (snippet) {
+ return { insertText: snippet };
+ }
+ return undefined;
}
+ }, {
+ pasteMimeTypes: ['text/uri-list']
});
}
diff --git a/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts b/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts
index 2ad71ec0516..01daa70085f 100644
--- a/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts
+++ b/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts
@@ -25,19 +25,22 @@ const imageFileExtensions = new Set<string>([
export function registerDropIntoEditor(selector: vscode.DocumentSelector) {
return vscode.languages.registerDocumentOnDropEditProvider(selector, new class implements vscode.DocumentOnDropEditProvider {
- async provideDocumentOnDropEdits(document: vscode.TextDocument, position: vscode.Position, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.SnippetTextEdit | undefined> {
+ async provideDocumentOnDropEdits(document: vscode.TextDocument, _position: vscode.Position, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.DocumentDropEdit | undefined> {
const enabled = vscode.workspace.getConfiguration('markdown', document).get('editor.drop.enabled', true);
if (!enabled) {
- return;
+ return undefined;
}
- const replacementRange = new vscode.Range(position, position);
- return tryInsertUriList(document, replacementRange, dataTransfer, token);
+ const snippet = await tryGetUriListSnippet(document, dataTransfer, token);
+ if (snippet) {
+ return { insertText: snippet };
+ }
+ return undefined;
}
});
}
-export async function tryInsertUriList(document: vscode.TextDocument, replacementRange: vscode.Range, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.SnippetTextEdit | undefined> {
+export async function tryGetUriListSnippet(document: vscode.TextDocument, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.SnippetString | undefined> {
const urlList = await dataTransfer.get('text/uri-list')?.asString();
if (!urlList || token.isCancellationRequested) {
return undefined;
@@ -72,5 +75,5 @@ export async function tryInsertUriList(document: vscode.TextDocument, replacemen
}
});
- return new vscode.SnippetTextEdit(replacementRange, snippet);
+ return snippet;
}
diff --git a/extensions/markdown-language-features/src/languageFeatures/rename.ts b/extensions/markdown-language-features/src/languageFeatures/rename.ts
index db06b7eeb9c..955581b9d97 100644
--- a/extensions/markdown-language-features/src/languageFeatures/rename.ts
+++ b/extensions/markdown-language-features/src/languageFeatures/rename.ts
@@ -142,7 +142,7 @@ export class MdRenameProvider extends Disposable implements vscode.RenameProvide
return this.renameExternalLink(allRefsInfo, newName);
} else if (triggerRef.kind === 'header' || (triggerRef.kind === 'link' && triggerRef.link.source.fragmentRange?.contains(position) && (triggerRef.link.kind === 'definition' || triggerRef.link.kind === 'link' && triggerRef.link.href.kind === 'internal'))) {
return this.renameFragment(allRefsInfo, newName);
- } else if (triggerRef.kind === 'link' && !triggerRef.link.source.fragmentRange?.contains(position) && triggerRef.link.kind === 'link' && triggerRef.link.href.kind === 'internal') {
+ } else if (triggerRef.kind === 'link' && !triggerRef.link.source.fragmentRange?.contains(position) && (triggerRef.link.kind === 'link' || triggerRef.link.kind === 'definition') && triggerRef.link.href.kind === 'internal') {
return this.renameFilePath(triggerRef.link.source.resource, triggerRef.link.href, allRefsInfo, newName);
}
diff --git a/extensions/markdown-language-features/src/test/rename.test.ts b/extensions/markdown-language-features/src/test/rename.test.ts
index 53839071ea4..6560055823d 100644
--- a/extensions/markdown-language-features/src/test/rename.test.ts
+++ b/extensions/markdown-language-features/src/test/rename.test.ts
@@ -614,4 +614,79 @@ suite('markdown: rename', () => {
]
});
});
+
+ test('Rename on definition path should update all references to path', async () => {
+ const uri = workspacePath('doc.md');
+ const doc = new InMemoryDocument(uri, joinLines(
+ `[ref text][ref]`,
+ `[direct](/file)`,
+ `[ref]: /file`, // rename here
+ ));
+
+ const workspace = new InMemoryWorkspaceMarkdownDocuments([doc]);
+
+ const preparedInfo = await prepareRename(doc, new vscode.Position(2, 10), workspace);
+ assert.strictEqual(preparedInfo!.placeholder, '/file');
+ assertRangeEqual(preparedInfo!.range, new vscode.Range(2, 7, 2, 12));
+
+ const edit = await getRenameEdits(doc, new vscode.Position(2, 10), "/newFile", workspace);
+ assertEditsEqual(edit!, {
+ uri, edits: [
+ new vscode.TextEdit(new vscode.Range(1, 9, 1, 14), '/newFile'),
+ new vscode.TextEdit(new vscode.Range(2, 7, 2, 12), '/newFile'),
+ ]
+ });
+ });
+
+ test('Rename on definition path where file exists should also update file', async () => {
+ const uri1 = workspacePath('doc.md');
+ const doc1 = new InMemoryDocument(uri1, joinLines(
+ `[ref text][ref]`,
+ `[direct](/doc2)`,
+ `[ref]: /doc2`, // rename here
+ ));
+
+ const uri2 = workspacePath('doc2.md');
+ const doc2 = new InMemoryDocument(uri2, joinLines());
+
+ const workspace = new InMemoryWorkspaceMarkdownDocuments([doc1, doc2]);
+
+ const preparedInfo = await prepareRename(doc1, new vscode.Position(2, 10), workspace);
+ assert.strictEqual(preparedInfo!.placeholder, '/doc2');
+ assertRangeEqual(preparedInfo!.range, new vscode.Range(2, 7, 2, 12));
+
+ const edit = await getRenameEdits(doc1, new vscode.Position(2, 10), "/new-doc", workspace);
+ assertEditsEqual(edit!, {
+ uri: uri1, edits: [
+ new vscode.TextEdit(new vscode.Range(1, 9, 1, 14), '/new-doc'),
+ new vscode.TextEdit(new vscode.Range(2, 7, 2, 12), '/new-doc'),
+ ]
+ }, {
+ originalUri: uri2,
+ newUri: workspacePath('new-doc.md')
+ });
+ });
+
+ test('Rename on definition path header should update all references to header', async () => {
+ const uri = workspacePath('doc.md');
+ const doc = new InMemoryDocument(uri, joinLines(
+ `[ref text][ref]`,
+ `[direct](/file#header)`,
+ `[ref]: /file#header`, // rename here
+ ));
+
+ const workspace = new InMemoryWorkspaceMarkdownDocuments([doc]);
+
+ const preparedInfo = await prepareRename(doc, new vscode.Position(2, 16), workspace);
+ assert.strictEqual(preparedInfo!.placeholder, 'header');
+ assertRangeEqual(preparedInfo!.range, new vscode.Range(2, 13, 2, 19));
+
+ const edit = await getRenameEdits(doc, new vscode.Position(2, 16), "New Header", workspace);
+ assertEditsEqual(edit!, {
+ uri, edits: [
+ new vscode.TextEdit(new vscode.Range(1, 15, 1, 21), 'new-header'),
+ new vscode.TextEdit(new vscode.Range(2, 13, 2, 19), 'new-header'),
+ ]
+ });
+ });
});
diff --git a/extensions/npm/src/tasks.ts b/extensions/npm/src/tasks.ts
index dc28ed7f4ed..676914a2dfb 100644
--- a/extensions/npm/src/tasks.ts
+++ b/extensions/npm/src/tasks.ts
@@ -12,10 +12,12 @@ import * as path from 'path';
import * as fs from 'fs';
import * as minimatch from 'minimatch';
import * as nls from 'vscode-nls';
+import { Utils } from 'vscode-uri';
import { findPreferredPM } from './preferred-pm';
import { readScripts } from './readScripts';
const localize = nls.loadMessageBundle();
+const excludeRegex = new RegExp('^(node_modules|.vscode-test)$', 'i');
export interface INpmTaskDefinition extends TaskDefinition {
script: string;
@@ -156,7 +158,7 @@ export async function hasNpmScripts(): Promise<boolean> {
}
try {
for (const folder of folders) {
- if (isAutoDetectionEnabled(folder)) {
+ if (isAutoDetectionEnabled(folder) && !excludeRegex.test(Utils.basename(folder.uri))) {
const relativePattern = new RelativePattern(folder, '**/package.json');
const paths = await workspace.findFiles(relativePattern, '**/node_modules/**');
if (paths.length > 0) {
@@ -182,7 +184,7 @@ async function detectNpmScripts(context: ExtensionContext, showWarning: boolean)
}
try {
for (const folder of folders) {
- if (isAutoDetectionEnabled(folder)) {
+ if (isAutoDetectionEnabled(folder) && !excludeRegex.test(Utils.basename(folder.uri))) {
const relativePattern = new RelativePattern(folder, '**/package.json');
const paths = await workspace.findFiles(relativePattern, '**/{node_modules,.vscode-test}/**');
for (const path of paths) {
@@ -206,6 +208,9 @@ export async function detectNpmScriptsForFolder(context: ExtensionContext, folde
const folderTasks: IFolderTaskItem[] = [];
try {
+ if (excludeRegex.test(Utils.basename(folder))) {
+ return folderTasks;
+ }
const relativePattern = new RelativePattern(folder.fsPath, '**/package.json');
const paths = await workspace.findFiles(relativePattern, '**/node_modules/**');
diff --git a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json
index 70b57d594fe..b37fd6b0083 100644
--- a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json
+++ b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json
@@ -65,7 +65,7 @@
}
},
{
- "scope": ["meta.embedded", "source.groovy.embedded"],
+ "scope": ["meta.embedded", "source.groovy.embedded", "meta.jsx.children"],
"settings": {
//"background": "#002451",
"foreground": "#FFFFFF"
diff --git a/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts b/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts
index c35aa35aee0..bc0ac10388b 100644
--- a/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts
+++ b/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts
@@ -174,6 +174,7 @@ export default class FileConfigurationManager extends Disposable {
document);
const preferences: Proto.UserPreferences = {
+ ...config.get('unstable'),
quotePreference: this.getQuoteStylePreference(preferencesConfig),
importModuleSpecifierPreference: getImportModuleSpecifierPreference(preferencesConfig),
importModuleSpecifierEnding: getImportModuleSpecifierEndingPreference(preferencesConfig),
diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/ipynb.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/ipynb.test.ts
index 44359de5e84..b73025ab2e7 100644
--- a/extensions/vscode-api-tests/src/singlefolder-tests/ipynb.test.ts
+++ b/extensions/vscode-api-tests/src/singlefolder-tests/ipynb.test.ts
@@ -18,9 +18,9 @@ import * as vscode from 'vscode';
const notebookEditor = vscode.window.activeNotebookEditor;
assert.ok(notebookEditor);
- assert.strictEqual(notebookEditor.document.cellCount, 2);
- assert.strictEqual(notebookEditor.document.cellAt(0).kind, vscode.NotebookCellKind.Markup);
- assert.strictEqual(notebookEditor.document.cellAt(1).kind, vscode.NotebookCellKind.Code);
- assert.strictEqual(notebookEditor.document.cellAt(1).outputs.length, 1);
+ assert.strictEqual(notebookEditor.notebook.cellCount, 2);
+ assert.strictEqual(notebookEditor.notebook.cellAt(0).kind, vscode.NotebookCellKind.Markup);
+ assert.strictEqual(notebookEditor.notebook.cellAt(1).kind, vscode.NotebookCellKind.Code);
+ assert.strictEqual(notebookEditor.notebook.cellAt(1).outputs.length, 1);
});
});
diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts
index 21b798dfbfd..12b79163769 100644
--- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts
+++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts
@@ -75,11 +75,11 @@ import * as utils from '../utils';
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const editor = await vscode.window.showNotebookDocument(uri);
- assert.strictEqual(uri.toString(), editor.document.uri.toString());
+ assert.strictEqual(uri.toString(), editor.notebook.uri.toString());
- assert.strictEqual(notebookDocumentsFromOnDidOpen.has(editor.document), true);
+ assert.strictEqual(notebookDocumentsFromOnDidOpen.has(editor.notebook), true);
- const includes = vscode.workspace.notebookDocuments.includes(editor.document);
+ const includes = vscode.workspace.notebookDocuments.includes(editor.notebook);
assert.strictEqual(true, includes);
sub.dispose();
@@ -104,7 +104,7 @@ import * as utils from '../utils';
const resource = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const editor = await vscode.window.showNotebookDocument(resource);
assert.ok(await openedEditor);
- assert.strictEqual(editor.document.uri.toString(), resource.toString());
+ assert.strictEqual(editor.notebook.uri.toString(), resource.toString());
});
test('Active/Visible Editor', async function () {
diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts
index f863bf014b6..c4d4733578a 100644
--- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts
+++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts
@@ -77,7 +77,7 @@ export class Kernel {
function getFocusedCell(editor?: vscode.NotebookEditor) {
- return editor ? editor.document.cellAt(editor.selections[0].start) : undefined;
+ return editor ? editor.notebook.cellAt(editor.selections[0].start) : undefined;
}
async function assertKernel(kernel: Kernel, notebook: vscode.NotebookDocument): Promise<void> {
@@ -204,12 +204,12 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
const cellsChangeEvent = asPromise<vscode.NotebookDocumentChangeEvent>(vscode.workspace.onDidChangeNotebookDocument);
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
const cellChangeEventRet = await cellsChangeEvent;
- assert.strictEqual(cellChangeEventRet.notebook, editor.document);
+ assert.strictEqual(cellChangeEventRet.notebook, editor.notebook);
assert.strictEqual(cellChangeEventRet.contentChanges.length, 1);
assert.deepStrictEqual(cellChangeEventRet.contentChanges[0], <vscode.NotebookDocumentContentChange>{
range: new vscode.NotebookRange(1, 1),
removedCells: [],
- addedCells: [editor.document.cellAt(1)]
+ addedCells: [editor.notebook.cellAt(1)]
});
const moveCellEvent = asPromise<vscode.NotebookDocumentChangeEvent>(vscode.workspace.onDidChangeNotebookDocument);
@@ -220,11 +220,11 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
await vscode.commands.executeCommand('notebook.cell.execute');
const cellOutputsAddedRet = await cellOutputChange;
- assert.strictEqual(cellOutputsAddedRet.notebook.uri.toString(), editor.document.uri.toString());
+ assert.strictEqual(cellOutputsAddedRet.notebook.uri.toString(), editor.notebook.uri.toString());
assert.strictEqual(cellOutputsAddedRet.metadata, undefined);
assert.strictEqual(cellOutputsAddedRet.contentChanges.length, 0);
assert.strictEqual(cellOutputsAddedRet.cellChanges.length, 1);
- assert.deepStrictEqual(cellOutputsAddedRet.cellChanges[0].cell, editor.document.cellAt(0));
+ assert.deepStrictEqual(cellOutputsAddedRet.cellChanges[0].cell, editor.notebook.cellAt(0));
assert.deepStrictEqual(cellOutputsAddedRet.cellChanges[0].executionSummary, { executionOrder: undefined, success: undefined, timing: undefined }); // TODO@jrieken should this be undefined instead all empty?
assert.strictEqual(cellOutputsAddedRet.cellChanges[0].document, undefined);
assert.strictEqual(cellOutputsAddedRet.cellChanges[0].metadata, undefined);
@@ -235,15 +235,15 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
await vscode.commands.executeCommand('notebook.cell.clearOutputs');
const cellOutputsCleardRet = await cellOutputClear;
assert.deepStrictEqual(cellOutputsCleardRet, <vscode.NotebookDocumentChangeEvent>{
- notebook: editor.document,
+ notebook: editor.notebook,
metadata: undefined,
contentChanges: [],
cellChanges: [{
- cell: editor.document.cellAt(0),
+ cell: editor.notebook.cellAt(0),
document: undefined,
executionSummary: undefined,
metadata: undefined,
- outputs: editor.document.cellAt(0).outputs
+ outputs: editor.notebook.cellAt(0).outputs
}],
});
assert.strictEqual(cellOutputsCleardRet.cellChanges[0].cell.outputs.length, 0);
@@ -289,21 +289,21 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
const editor = await vscode.window.showNotebookDocument(notebook);
const notebookChangeEvent = asPromise<vscode.NotebookDocumentChangeEvent>(vscode.workspace.onDidChangeNotebookDocument);
- const version = editor.document.version;
+ const version = editor.notebook.version;
await editor.edit(editBuilder => {
editBuilder.replaceCells(1, 0, [{ kind: vscode.NotebookCellKind.Code, languageId: 'javascript', value: 'test 2', outputs: [], metadata: undefined }]);
editBuilder.replaceCellMetadata(0, { inputCollapsed: false });
});
await notebookChangeEvent;
- assert.strictEqual(editor.document.cellCount, 3);
- assert.strictEqual(editor.document.cellAt(0)?.metadata.inputCollapsed, false);
- assert.strictEqual(version + 1, editor.document.version);
+ assert.strictEqual(editor.notebook.cellCount, 3);
+ assert.strictEqual(editor.notebook.cellAt(0)?.metadata.inputCollapsed, false);
+ assert.strictEqual(version + 1, editor.notebook.version);
await vscode.commands.executeCommand('undo');
- assert.strictEqual(version + 2, editor.document.version);
- assert.strictEqual(editor.document.cellAt(0)?.metadata.inputCollapsed, undefined);
- assert.strictEqual(editor.document.cellCount, 2);
+ assert.strictEqual(version + 2, editor.notebook.version);
+ assert.strictEqual(editor.notebook.cellAt(0)?.metadata.inputCollapsed, undefined);
+ assert.strictEqual(editor.notebook.cellCount, 2);
});
// #126371
@@ -326,7 +326,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'test');
assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript');
- const secondCell = editor.document.cellAt(1);
+ const secondCell = editor.notebook.cellAt(1);
assert.strictEqual(secondCell.outputs.length, 1);
assert.deepStrictEqual(secondCell.outputs[0].metadata, { testOutputMetadata: true, ['text/plain']: { testOutputItemMetadata: true } });
assert.strictEqual(secondCell.outputs[0].items.length, 1);
@@ -353,22 +353,22 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
let activeCell = getFocusedCell(editor);
assert.notStrictEqual(getFocusedCell(editor), undefined);
assert.strictEqual(activeCell!.document.getText(), '');
- assert.strictEqual(editor.document.cellCount, 4);
- assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 1);
+ assert.strictEqual(editor.notebook.cellCount, 4);
+ assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 1);
// ---- focus bottom ---- //
await vscode.commands.executeCommand('notebook.focusBottom');
activeCell = getFocusedCell(editor);
- assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 3);
+ assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 3);
// ---- focus top and then copy down ---- //
await vscode.commands.executeCommand('notebook.focusTop');
activeCell = getFocusedCell(editor);
- assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 0);
+ assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 0);
await vscode.commands.executeCommand('notebook.cell.copyDown');
activeCell = getFocusedCell(editor);
- assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 1);
+ assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 1);
assert.strictEqual(activeCell?.document.getText(), 'test');
{
@@ -381,25 +381,25 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
}
activeCell = getFocusedCell(editor);
- assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 1);
+ assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 1);
assert.strictEqual(activeCell?.document.getText(), '');
// ---- focus top and then copy up ---- //
await vscode.commands.executeCommand('notebook.focusTop');
await vscode.commands.executeCommand('notebook.cell.copyUp');
- assert.strictEqual(editor.document.cellCount, 5);
- assert.strictEqual(editor.document.cellAt(0).document.getText(), 'test');
- assert.strictEqual(editor.document.cellAt(1).document.getText(), 'test');
- assert.strictEqual(editor.document.cellAt(2).document.getText(), '');
- assert.strictEqual(editor.document.cellAt(3).document.getText(), '');
+ assert.strictEqual(editor.notebook.cellCount, 5);
+ assert.strictEqual(editor.notebook.cellAt(0).document.getText(), 'test');
+ assert.strictEqual(editor.notebook.cellAt(1).document.getText(), 'test');
+ assert.strictEqual(editor.notebook.cellAt(2).document.getText(), '');
+ assert.strictEqual(editor.notebook.cellAt(3).document.getText(), '');
activeCell = getFocusedCell(editor);
- assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 0);
+ assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 0);
// ---- move up and down ---- //
await vscode.commands.executeCommand('notebook.cell.moveDown');
- assert.strictEqual(editor.document.getCells().indexOf(getFocusedCell(editor)!), 1,
+ assert.strictEqual(editor.notebook.getCells().indexOf(getFocusedCell(editor)!), 1,
`first move down, active cell ${getFocusedCell(editor)!.document.uri.toString()}, ${getFocusedCell(editor)!.document.getText()}`);
await vscode.commands.executeCommand('workbench.action.files.save');
@@ -427,7 +427,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
// assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
// const editor = vscode.window.activeNotebookEditor!;
- // const cell = editor.document.cellAt(0);
+ // const cell = editor.notebook.cellAt(0);
// assert.strictEqual(cell.outputs.length, 0);
// currentKernelProvider.setHasKernels(false);
@@ -452,7 +452,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
const editor = vscode.window.activeNotebookEditor!;
- const cell = editor.document.cellAt(0);
+ const cell = editor.notebook.cellAt(0);
await vscode.commands.executeCommand('notebook.execute');
assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work
@@ -463,7 +463,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
const editor = vscode.window.activeNotebookEditor!;
- const cell = editor.document.cellAt(0);
+ const cell = editor.notebook.cellAt(0);
await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => {
await vscode.commands.executeCommand('notebook.execute');
@@ -484,7 +484,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
await vscode.commands.executeCommand('notebook.cell.execute', { start: 0, end: 1 }, resource);
await event;
assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
- assert.strictEqual(vscode.window.activeNotebookEditor?.document.uri.fsPath, secondResource.fsPath);
+ assert.strictEqual(vscode.window.activeNotebookEditor?.notebook.uri.fsPath, secondResource.fsPath);
});
});
@@ -524,7 +524,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
const editor = vscode.window.activeNotebookEditor!;
- const cell = editor.document.cellAt(0);
+ const cell = editor.notebook.cellAt(0);
await withEvent<vscode.NotebookDocumentChangeEvent>(vscode.workspace.onDidChangeNotebookDocument, async (event) => {
await vscode.commands.executeCommand('notebook.execute');
@@ -544,7 +544,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
await vscode.commands.executeCommand('notebook.execute', resource);
await event;
assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
- assert.strictEqual(vscode.window.activeNotebookEditor?.document.uri.fsPath, secondResource.fsPath);
+ assert.strictEqual(vscode.window.activeNotebookEditor?.notebook.uri.fsPath, secondResource.fsPath);
});
});
@@ -553,7 +553,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
const editor = await vscode.window.showNotebookDocument(notebook);
assert.strictEqual(vscode.window.activeNotebookEditor === editor, true, 'notebook first');
- const cell = editor.document.cellAt(0);
+ const cell = editor.notebook.cellAt(0);
const alternativeKernel = new class extends Kernel {
constructor() {
@@ -597,7 +597,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
const resource = await createRandomNotebookFile();
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
const editor = vscode.window.activeNotebookEditor!;
- const cell = editor.document.cellAt(0);
+ const cell = editor.notebook.cellAt(0);
vscode.commands.executeCommand('notebook.cell.execute');
let eventCount = 0;
@@ -636,8 +636,8 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
const activeCell = getFocusedCell(editor);
assert.notStrictEqual(getFocusedCell(editor), undefined);
assert.strictEqual(activeCell!.document.getText(), '');
- assert.strictEqual(editor.document.cellCount, 4);
- assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 1);
+ assert.strictEqual(editor.notebook.cellCount, 4);
+ assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 1);
await withEvent(vscode.workspace.onDidChangeTextDocument, async event => {
const edit = new vscode.WorkspaceEdit();
@@ -645,7 +645,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
await vscode.workspace.applyEdit(edit);
await event;
assert.strictEqual(vscode.window.activeNotebookEditor === editor, true);
- assert.deepStrictEqual(editor.document.cellAt(1), getFocusedCell(editor));
+ assert.deepStrictEqual(editor.notebook.cellAt(1), getFocusedCell(editor));
assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'var abc = 0;');
});
});
@@ -667,8 +667,8 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
// make sure that the previous dirty editor is still restored in the extension host and no data loss
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true);
- assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
- assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 4);
+ assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
+ assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellCount, 4);
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'var abc = 0;');
});
@@ -692,15 +692,15 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
// switch to the first editor
await vscode.window.showNotebookDocument(notebook);
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true);
- assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
- assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 4);
+ assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
+ assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellCount, 4);
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'var abc = 0;');
// switch to the second editor
await vscode.window.showNotebookDocument(secondNotebook);
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true);
- assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
- assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 3);
+ assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
+ assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellCount, 3);
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), '');
});
@@ -721,7 +721,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.languageId, 'typescript');
assert.notStrictEqual(firstNotebookEditor, secondNotebookEditor);
- assert.strictEqual(firstNotebookEditor?.document, secondNotebookEditor?.document, 'split notebook editors share the same document');
+ assert.strictEqual(firstNotebookEditor?.notebook, secondNotebookEditor?.notebook, 'split notebook editors share the same document');
});
@@ -737,7 +737,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
// await vscode.commands.executeCommand('vscode.open', cell.document.uri, vscode.ViewColumn.Active);
assert.strictEqual(!!vscode.window.activeNotebookEditor, true);
- assert.strictEqual(vscode.window.activeNotebookEditor!.document.uri.toString(), document.uri.toString());
+ assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.uri.toString(), document.uri.toString());
});
test('Cannot open notebook from cell-uri with vscode.open-command', async function () {
@@ -752,7 +752,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
// removes the fragment if it matches something numeric. For notebooks that's not wanted...
await vscode.commands.executeCommand('vscode.open', cell.document.uri);
- assert.strictEqual(vscode.window.activeNotebookEditor!.document.uri.toString(), document.uri.toString());
+ assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.uri.toString(), document.uri.toString());
});
test('#97830, #97764. Support switch to other editor types', async function () {
@@ -805,15 +805,15 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
await vscode.commands.executeCommand('notebook.cell.copyDown');
await vscode.commands.executeCommand('notebook.cell.edit');
activeCell = getFocusedCell(vscode.window.activeNotebookEditor);
- assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1);
+ assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.getCells().indexOf(activeCell!), 1);
assert.strictEqual(activeCell?.document.getText(), 'test');
const edit = new vscode.WorkspaceEdit();
edit.insert(getFocusedCell(vscode.window.activeNotebookEditor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;');
await vscode.workspace.applyEdit(edit);
- assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().length, 3);
- assert.notStrictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0).document.getText(), vscode.window.activeNotebookEditor!.document.cellAt(1).document.getText());
+ assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.getCells().length, 3);
+ assert.notStrictEqual(vscode.window.activeNotebookEditor!.notebook.cellAt(0).document.getText(), vscode.window.activeNotebookEditor!.notebook.cellAt(1).document.getText());
await closeAllEditors();
});
@@ -876,7 +876,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
const resource = await createRandomNotebookFile();
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
const editor = vscode.window.activeNotebookEditor!;
- const cell = editor.document.cellAt(0);
+ const cell = editor.notebook.cellAt(0);
assert.strictEqual(cell.executionSummary?.success, undefined);
assert.strictEqual(cell.executionSummary?.executionOrder, undefined);
@@ -999,7 +999,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
const notebook = await openRandomNotebookDocument();
const editor = await vscode.window.showNotebookDocument(notebook);
- assert.strictEqual(editor.document.metadata.custom?.testMetadata, false);
+ assert.strictEqual(editor.notebook.metadata.custom?.testMetadata, false);
assert.strictEqual(getFocusedCell(editor)?.metadata.custom?.testCellMetadata, 123);
assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript');
});
diff --git a/package.json b/package.json
index 9ac0994ecec..cc87e68f1eb 100644
--- a/package.json
+++ b/package.json
@@ -200,7 +200,7 @@
"style-loader": "^1.0.0",
"ts-loader": "^9.2.7",
"tsec": "0.1.4",
- "typescript": "^4.8.0-dev.20220518",
+ "typescript": "^4.8.0-dev.20220608",
"typescript-formatter": "7.1.0",
"underscore": "^1.12.1",
"util": "^0.12.4",
diff --git a/src/vs/editor/common/languages.ts b/src/vs/editor/common/languages.ts
index 6ad570fcd54..bb5e3134ec5 100644
--- a/src/vs/editor/common/languages.ts
+++ b/src/vs/editor/common/languages.ts
@@ -724,10 +724,21 @@ export interface CodeActionProvider {
/**
* @internal
*/
+export interface DocumentPasteEdit {
+ insertText: string | { snippet: string };
+ additionalEdit?: WorkspaceEdit;
+}
+
+/**
+ * @internal
+ */
export interface DocumentPasteEditProvider {
- prepareDocumentPaste?(model: model.ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<undefined | VSDataTransfer>;
- provideDocumentPasteEdits(model: model.ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<WorkspaceEdit | SnippetTextEdit | undefined>;
+ readonly pasteMimeTypes: readonly string[];
+
+ prepareDocumentPaste?(model: model.ITextModel, selections: readonly Selection[], dataTransfer: VSDataTransfer, token: CancellationToken): Promise<undefined | VSDataTransfer>;
+
+ provideDocumentPasteEdits(model: model.ITextModel, selections: readonly Selection[], dataTransfer: VSDataTransfer, token: CancellationToken): Promise<DocumentPasteEdit | undefined>;
}
/**
@@ -1123,11 +1134,6 @@ export interface DocumentSymbolProvider {
export type TextEdit = { range: IRange; text: string; eol?: model.EndOfLineSequence };
-export interface SnippetTextEdit {
- range: IRange;
- snippet: string;
-}
-
/**
* Interface used to format a model
*/
@@ -1800,10 +1806,17 @@ export enum ExternalUriOpenerPriority {
Preferred = 3,
}
+/**
+ * @internal
+ */
+export interface DocumentOnDropEdit {
+ insertText: string | { snippet: string };
+ additionalEdit?: WorkspaceEdit;
+}
/**
* @internal
*/
export interface DocumentOnDropEditProvider {
- provideDocumentOnDropEdits(model: model.ITextModel, position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): ProviderResult<SnippetTextEdit>;
+ provideDocumentOnDropEdits(model: model.ITextModel, position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): ProviderResult<DocumentOnDropEdit>;
}
diff --git a/src/vs/editor/contrib/copyPaste/browser/copyPasteController.ts b/src/vs/editor/contrib/copyPaste/browser/copyPasteController.ts
index 41c53942b70..2ad4c28a6eb 100644
--- a/src/vs/editor/contrib/copyPaste/browser/copyPasteController.ts
+++ b/src/vs/editor/contrib/copyPaste/browser/copyPasteController.ts
@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
+import { DataTransfers } from 'vs/base/browser/dnd';
import { addDisposableListener } from 'vs/base/browser/dom';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
import { CancellationToken } from 'vs/base/common/cancellation';
@@ -15,26 +16,26 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IBulkEditService, ResourceEdit } from 'vs/editor/browser/services/bulkEditService';
import { Selection } from 'vs/editor/common/core/selection';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
-import { DocumentPasteEditProvider, SnippetTextEdit, WorkspaceEdit } from 'vs/editor/common/languages';
+import { DocumentPasteEdit, DocumentPasteEditProvider } from 'vs/editor/common/languages';
import { ITextModel } from 'vs/editor/common/model';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState';
import { performSnippetEdit } from 'vs/editor/contrib/snippet/browser/snippetController2';
+import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
const vscodeClipboardMime = 'application/vnd.code.copyId';
const defaultPasteEditProvider = new class implements DocumentPasteEditProvider {
- async provideDocumentPasteEdits(model: ITextModel, selection: Selection, dataTransfer: VSDataTransfer, _token: CancellationToken): Promise<WorkspaceEdit | undefined> {
+ pasteMimeTypes = [Mimes.text, 'text'];
+
+ async provideDocumentPasteEdits(model: ITextModel, selections: Selection[], dataTransfer: VSDataTransfer, _token: CancellationToken): Promise<DocumentPasteEdit | undefined> {
const textDataTransfer = dataTransfer.get(Mimes.text) ?? dataTransfer.get('text');
if (textDataTransfer) {
const text = await textDataTransfer.asString();
return {
- edits: [{
- resource: model.uri,
- edit: { range: selection, text },
- }]
+ insertText: text
};
}
@@ -76,8 +77,8 @@ export class CopyPasteController extends Disposable implements IEditorContributi
}
const model = editor.getModel();
- const selection = this._editor.getSelection();
- if (!model || !selection) {
+ const selections = this._editor.getSelections();
+ if (!model || !selections?.length) {
return;
}
@@ -98,7 +99,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
const promise = createCancelablePromise(async token => {
const results = await Promise.all(providers.map(provider => {
- return provider.prepareDocumentPaste!(model, selection, dataTransfer, token);
+ return provider.prepareDocumentPaste!(model, selections, dataTransfer, token);
}));
for (const result of results) {
@@ -115,8 +116,8 @@ export class CopyPasteController extends Disposable implements IEditorContributi
}));
this._register(addDisposableListener(container, 'paste', async (e: ClipboardEvent) => {
- const selection = this._editor.getSelection();
- if (!e.clipboardData || !selection || !editor.hasModel()) {
+ const selections = this._editor.getSelections();
+ if (!e.clipboardData || !selections?.length || !editor.hasModel()) {
return;
}
@@ -125,21 +126,20 @@ export class CopyPasteController extends Disposable implements IEditorContributi
return;
}
- const originalDocVersion = model.getVersionId();
-
- const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model);
- if (!providers.length) {
+ const handle = e.clipboardData?.getData(vscodeClipboardMime);
+ if (typeof handle !== 'string') {
return;
}
- const handle = e.clipboardData?.getData(vscodeClipboardMime);
- if (typeof handle !== 'string') {
+ const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model);
+ if (!providers.length) {
return;
}
e.preventDefault();
e.stopImmediatePropagation();
+ const originalDocVersion = model.getVersionId();
const tokenSource = new EditorStateCancellationTokenSource(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Selection);
try {
@@ -148,7 +148,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
if (handle && this._currentClipboardItem?.handle === handle) {
const toMergeDataTransfer = await this._currentClipboardItem.dataTransferPromise;
toMergeDataTransfer.forEach((value, key) => {
- dataTransfer.append(key, value);
+ dataTransfer.replace(key, value);
});
}
@@ -163,16 +163,25 @@ export class CopyPasteController extends Disposable implements IEditorContributi
dataTransfer.delete(vscodeClipboardMime);
for (const provider of [...providers, defaultPasteEditProvider]) {
- const edit = await provider.provideDocumentPasteEdits(model, selection, dataTransfer, tokenSource.token);
+ if (!provider.pasteMimeTypes.some(type => {
+ if (type.toLowerCase() === DataTransfers.FILES.toLowerCase()) {
+ return [...dataTransfer.values()].some(item => item.asFile());
+ }
+ return dataTransfer.has(type);
+ })) {
+ continue;
+ }
+
+ const edit = await provider.provideDocumentPasteEdits(model, selections, dataTransfer, tokenSource.token);
if (originalDocVersion !== model.getVersionId()) {
return;
}
if (edit) {
- if ((edit as WorkspaceEdit).edits) {
- await this._bulkEditService.apply(ResourceEdit.convert(edit as WorkspaceEdit), { editor });
- } else {
- performSnippetEdit(editor, edit as SnippetTextEdit);
+ performSnippetEdit(editor, typeof edit.insertText === 'string' ? SnippetParser.escape(edit.insertText) : edit.insertText.snippet, selections);
+
+ if (edit.additionalEdit) {
+ await this._bulkEditService.apply(ResourceEdit.convert(edit.additionalEdit), { editor });
}
return;
}
diff --git a/src/vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution.ts b/src/vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution.ts
index 48bac674986..8254c5faf12 100644
--- a/src/vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution.ts
+++ b/src/vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution.ts
@@ -13,14 +13,17 @@ import { URI } from 'vs/base/common/uri';
import { toVSDataTransfer } from 'vs/editor/browser/dnd';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
+import { IBulkEditService, ResourceEdit } from 'vs/editor/browser/services/bulkEditService';
import { IPosition } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
+import { Selection, SelectionDirection } from 'vs/editor/common/core/selection';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
-import { DocumentOnDropEditProvider, SnippetTextEdit } from 'vs/editor/common/languages';
+import { DocumentOnDropEdit, DocumentOnDropEditProvider } from 'vs/editor/common/languages';
import { ITextModel } from 'vs/editor/common/model';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState';
import { performSnippetEdit } from 'vs/editor/contrib/snippet/browser/snippetController2';
+import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { extractEditorsDropData } from 'vs/platform/dnd/browser/dnd';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -37,6 +40,7 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
+ @IBulkEditService private readonly _bulkEditService: IBulkEditService,
) {
super();
@@ -87,7 +91,12 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
}
if (edit) {
- performSnippetEdit(editor, edit);
+ const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column);
+ performSnippetEdit(editor, typeof edit.insertText === 'string' ? SnippetParser.escape(edit.insertText) : edit.insertText.snippet, [Selection.fromRange(range, SelectionDirection.LTR)]);
+
+ if (edit.additionalEdit) {
+ await this._bulkEditService.apply(ResourceEdit.convert(edit.additionalEdit), { editor });
+ }
return;
}
}
@@ -121,24 +130,26 @@ class DefaultOnDropProvider implements DocumentOnDropEditProvider {
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService,
) { }
- async provideDocumentOnDropEdits(model: ITextModel, position: IPosition, dataTransfer: VSDataTransfer, _token: CancellationToken): Promise<SnippetTextEdit | undefined> {
- const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column);
-
+ async provideDocumentOnDropEdits(_model: ITextModel, _position: IPosition, dataTransfer: VSDataTransfer, _token: CancellationToken): Promise<DocumentOnDropEdit | undefined> {
const urlListEntry = dataTransfer.get('text/uri-list');
if (urlListEntry) {
const urlList = await urlListEntry.asString();
- return this.doUriListDrop(range, urlList);
+ const snippet = this.getUriListInsertText(urlList);
+ if (snippet) {
+ return { insertText: snippet };
+ }
}
const textEntry = dataTransfer.get('text') ?? dataTransfer.get(Mimes.text);
if (textEntry) {
const text = await textEntry.asString();
- return { range, snippet: text };
+ return { insertText: text };
}
+
return undefined;
}
- private doUriListDrop(range: Range, urlList: string): SnippetTextEdit | undefined {
+ private getUriListInsertText(urlList: string): string | undefined {
const uris: URI[] = [];
for (const resource of urlList.split('\n')) {
try {
@@ -152,7 +163,7 @@ class DefaultOnDropProvider implements DocumentOnDropEditProvider {
return;
}
- const snippet = uris
+ return uris
.map(uri => {
const root = this._workspaceContextService.getWorkspaceFolder(uri);
if (root) {
@@ -164,8 +175,6 @@ class DefaultOnDropProvider implements DocumentOnDropEditProvider {
return uri.fsPath;
})
.join(' ');
-
- return { range, snippet };
}
}
diff --git a/src/vs/editor/contrib/snippet/browser/snippetController2.ts b/src/vs/editor/contrib/snippet/browser/snippetController2.ts
index f226b74458d..bb8282d9ee5 100644
--- a/src/vs/editor/contrib/snippet/browser/snippetController2.ts
+++ b/src/vs/editor/contrib/snippet/browser/snippetController2.ts
@@ -9,9 +9,10 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorCommand, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
+import { ISelection } from 'vs/editor/common/core/selection';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
-import { CompletionItem, CompletionItemKind, CompletionItemProvider, SnippetTextEdit } from 'vs/editor/common/languages';
+import { CompletionItem, CompletionItemKind, CompletionItemProvider } from 'vs/editor/common/languages';
import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';
import { ITextModel } from 'vs/editor/common/model';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
@@ -335,13 +336,13 @@ registerEditorCommand(new CommandCtor({
// ---
-export function performSnippetEdit(editor: ICodeEditor, edit: SnippetTextEdit) {
+export function performSnippetEdit(editor: ICodeEditor, snippet: string, selections: ISelection[]): boolean {
const controller = SnippetController2.get(editor);
if (!controller) {
return false;
}
editor.focus();
- editor.setSelection(edit.range);
- controller.insert(edit.snippet);
+ editor.setSelections(selections ?? []);
+ controller.insert(snippet);
return controller.isInSnippet();
}
diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts
index 37a8579dcc5..19ce500b0f6 100644
--- a/src/vs/monaco.d.ts
+++ b/src/vs/monaco.d.ts
@@ -6758,11 +6758,6 @@ declare namespace monaco.languages {
eol?: editor.EndOfLineSequence;
};
- export interface SnippetTextEdit {
- range: IRange;
- snippet: string;
- }
-
/**
* Interface used to format a model
*/
diff --git a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts
index e9231a1df85..db9d8a87c0e 100644
--- a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts
+++ b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts
@@ -9,7 +9,7 @@ import { RemoteAuthorities } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { IProductService } from 'vs/platform/product/common/productService';
import { IRemoteAuthorityResolverService, IRemoteConnectionData, ResolvedAuthority, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
-import { getRemoteServerRootPath } from 'vs/platform/remote/common/remoteHosts';
+import { getRemoteServerRootPath, parseAuthorityWithOptionalPort } from 'vs/platform/remote/common/remoteHosts';
export class RemoteAuthorityResolverService extends Disposable implements IRemoteAuthorityResolverService {
@@ -62,12 +62,9 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot
private _doResolveAuthority(authority: string): ResolverResult {
const connectionToken = this._connectionTokens.get(authority) || this._connectionToken;
- if (authority.indexOf(':') >= 0) {
- const pieces = authority.split(':');
- return { authority: { authority, host: pieces[0], port: parseInt(pieces[1], 10), connectionToken } };
- }
- const port = (/^https:/.test(window.location.href) ? 443 : 80);
- return { authority: { authority, host: authority, port: port, connectionToken } };
+ const defaultPort = (/^https:/.test(window.location.href) ? 443 : 80);
+ const { host, port } = parseAuthorityWithOptionalPort(authority, defaultPort);
+ return { authority: { authority, host: host, port: port, connectionToken } };
}
_clearResolvedAuthority(authority: string): void {
diff --git a/src/vs/platform/remote/common/remoteHosts.ts b/src/vs/platform/remote/common/remoteHosts.ts
index 760033e5789..783ea2e0896 100644
--- a/src/vs/platform/remote/common/remoteHosts.ts
+++ b/src/vs/platform/remote/common/remoteHosts.ts
@@ -33,3 +33,46 @@ export function getRemoteName(authority: string | undefined): string | undefined
export function getRemoteServerRootPath(product: { quality?: string; commit?: string }): string {
return `/${product.quality ?? 'oss'}-${product.commit ?? 'dev'}`;
}
+
+export function parseAuthorityWithPort(authority: string): { host: string; port: number } {
+ const { host, port } = parseAuthority(authority);
+ if (typeof port === 'undefined') {
+ throw new Error(`Remote authority doesn't contain a port!`);
+ }
+ return { host, port };
+}
+
+export function parseAuthorityWithOptionalPort(authority: string, defaultPort: number): { host: string; port: number } {
+ let { host, port } = parseAuthority(authority);
+ if (typeof port === 'undefined') {
+ port = defaultPort;
+ }
+ return { host, port };
+}
+
+function parseAuthority(authority: string): { host: string; port: number | undefined } {
+ if (authority.indexOf('+') >= 0) {
+ throw new Error(`Remote authorities containing '+' need to be resolved!`);
+ }
+
+ // check for ipv6 with port
+ const m1 = authority.match(/^(\[[0-9a-z:]+\]):(\d+)$/);
+ if (m1) {
+ return { host: m1[1], port: parseInt(m1[2], 10) };
+ }
+
+ // check for ipv6 without port
+ const m2 = authority.match(/^(\[[0-9a-z:]+\])$/);
+ if (m2) {
+ return { host: m2[1], port: undefined };
+ }
+
+ // anything with a trailing port
+ const m3 = authority.match(/(.*):(\d+)$/);
+ if (m3) {
+ return { host: m3[1], port: parseInt(m3[2], 10) };
+ }
+
+ // doesn't contain a port
+ return { host: authority, port: undefined };
+}
diff --git a/src/vs/platform/remote/test/common/remoteHosts.test.ts b/src/vs/platform/remote/test/common/remoteHosts.test.ts
new file mode 100644
index 00000000000..da7349774f6
--- /dev/null
+++ b/src/vs/platform/remote/test/common/remoteHosts.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 assert from 'assert';
+import { parseAuthorityWithOptionalPort, parseAuthorityWithPort } from 'vs/platform/remote/common/remoteHosts';
+
+suite('remoteHosts', () => {
+
+ test('parseAuthority hostname', () => {
+ assert.deepStrictEqual(parseAuthorityWithPort('localhost:8080'), { host: 'localhost', port: 8080 });
+ });
+
+ test('parseAuthority ipv4', () => {
+ assert.deepStrictEqual(parseAuthorityWithPort('127.0.0.1:8080'), { host: '127.0.0.1', port: 8080 });
+ });
+
+ test('parseAuthority ipv6', () => {
+ assert.deepStrictEqual(parseAuthorityWithPort('[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080'), { host: '[2001:0db8:85a3:0000:0000:8a2e:0370:7334]', port: 8080 });
+ });
+
+ test('parseAuthorityWithOptionalPort hostname', () => {
+ assert.deepStrictEqual(parseAuthorityWithOptionalPort('localhost:8080', 123), { host: 'localhost', port: 8080 });
+ assert.deepStrictEqual(parseAuthorityWithOptionalPort('localhost', 123), { host: 'localhost', port: 123 });
+ });
+
+ test('parseAuthorityWithOptionalPort ipv4', () => {
+ assert.deepStrictEqual(parseAuthorityWithOptionalPort('127.0.0.1:8080', 123), { host: '127.0.0.1', port: 8080 });
+ assert.deepStrictEqual(parseAuthorityWithOptionalPort('127.0.0.1', 123), { host: '127.0.0.1', port: 123 });
+ });
+
+ test('parseAuthorityWithOptionalPort ipv6', () => {
+ assert.deepStrictEqual(parseAuthorityWithOptionalPort('[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080', 123), { host: '[2001:0db8:85a3:0000:0000:8a2e:0370:7334]', port: 8080 });
+ assert.deepStrictEqual(parseAuthorityWithOptionalPort('[2001:0db8:85a3:0000:0000:8a2e:0370:7334]', 123), { host: '[2001:0db8:85a3:0000:0000:8a2e:0370:7334]', port: 123 });
+ });
+
+});
diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts
index 1545d21d0c5..1e4a6f043d3 100644
--- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts
+++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts
@@ -30,7 +30,7 @@ import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'
import * as search from 'vs/workbench/contrib/search/common/search';
import * as typeh from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy';
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
-import { ExtHostContext, ExtHostLanguageFeaturesShape, ICallHierarchyItemDto, ICodeActionDto, ICodeActionProviderMetadataDto, IdentifiableInlineCompletion, IdentifiableInlineCompletions, IDocumentFilterDto, IIndentationRuleDto, IInlayHintDto, ILanguageConfigurationDto, ILanguageWordDefinitionDto, ILinkDto, ILocationDto, ILocationLinkDto, IOnEnterRuleDto, IRegExpDto, ISignatureHelpProviderMetadataDto, ISuggestDataDto, ISuggestDataDtoField, ISuggestResultDtoField, ITypeHierarchyItemDto, IWorkspaceEditDto, IWorkspaceSymbolDto, MainContext, MainThreadLanguageFeaturesShape, reviveWorkspaceEditDto } from '../common/extHost.protocol';
+import { ExtHostContext, ExtHostLanguageFeaturesShape, ICallHierarchyItemDto, ICodeActionDto, ICodeActionProviderMetadataDto, IdentifiableInlineCompletion, IdentifiableInlineCompletions, IDocumentFilterDto, IIndentationRuleDto, IInlayHintDto, ILanguageConfigurationDto, ILanguageWordDefinitionDto, ILinkDto, ILocationDto, ILocationLinkDto, IOnEnterRuleDto, IRegExpDto, ISignatureHelpProviderMetadataDto, ISuggestDataDto, ISuggestDataDtoField, ISuggestResultDtoField, ITypeHierarchyItemDto, IWorkspaceSymbolDto, MainContext, MainThreadLanguageFeaturesShape, reviveWorkspaceEditDto } from '../common/extHost.protocol';
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
export class MainThreadLanguageFeatures extends Disposable implements MainThreadLanguageFeaturesShape {
@@ -368,21 +368,22 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread
// --- copy paste action provider
- $registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean): void {
+ $registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean, pasteMimeTypes: readonly string[]): void {
const provider: languages.DocumentPasteEditProvider = {
+ pasteMimeTypes: pasteMimeTypes,
+
prepareDocumentPaste: supportsCopy
- ? async (model: ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<VSDataTransfer | undefined> => {
+ ? async (model: ITextModel, selections: Selection[], dataTransfer: VSDataTransfer, token: CancellationToken): Promise<VSDataTransfer | undefined> => {
const dataTransferDto = await typeConvert.DataTransfer.toDataTransferDTO(dataTransfer);
if (token.isCancellationRequested) {
return undefined;
}
- const result = await this._proxy.$prepareDocumentPaste(handle, model.uri, selection, dataTransferDto, token);
+ const result = await this._proxy.$prepareDocumentPaste(handle, model.uri, selections, dataTransferDto, token);
if (!result) {
return undefined;
}
-
const dataTransferOut = new VSDataTransfer();
result.items.forEach(([type, item]) => {
dataTransferOut.replace(type, createStringDataTransferItem(item.asString));
@@ -391,16 +392,17 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread
}
: undefined,
- provideDocumentPasteEdits: async (model: ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken) => {
+ provideDocumentPasteEdits: async (model: ITextModel, selections: Selection[], dataTransfer: VSDataTransfer, token: CancellationToken) => {
const d = await typeConvert.DataTransfer.toDataTransferDTO(dataTransfer);
- const result = await this._proxy.$providePasteEdits(handle, model.uri, selection, d, token);
+ const result = await this._proxy.$providePasteEdits(handle, model.uri, selections, d, token);
if (!result) {
- return;
- } else if ((result as IWorkspaceEditDto).edits) {
- return reviveWorkspaceEditDto(result as IWorkspaceEditDto);
- } else {
- return result as languages.SnippetTextEdit;
+ return undefined;
}
+
+ return {
+ insertText: result.insertText,
+ additionalEdit: result.additionalEdit ? reviveWorkspaceEditDto(result.additionalEdit) : undefined,
+ };
}
};
@@ -933,11 +935,18 @@ class MainThreadDocumentOnDropEditProvider implements languages.DocumentOnDropEd
private readonly _proxy: ExtHostLanguageFeaturesShape,
) { }
- async provideDocumentOnDropEdits(model: ITextModel, position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<languages.SnippetTextEdit | null | undefined> {
+ async provideDocumentOnDropEdits(model: ITextModel, position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<languages.DocumentOnDropEdit | null | undefined> {
const request = this.dataTransfers.add(dataTransfer);
try {
const dataTransferDto = await typeConvert.DataTransfer.toDataTransferDTO(dataTransfer);
- return await this._proxy.$provideDocumentOnDropEdits(this.handle, request.id, model.uri, position, dataTransferDto, token);
+ const edit = await this._proxy.$provideDocumentOnDropEdits(this.handle, request.id, model.uri, position, dataTransferDto, token);
+ if (!edit) {
+ return undefined;
+ }
+ return {
+ insertText: edit.insertText,
+ additionalEdit: reviveWorkspaceEditDto(edit.additionalEdit),
+ };
} finally {
request.dispose();
}
diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts
index e649eb3a21a..cd752d09994 100644
--- a/src/vs/workbench/api/common/extHost.api.impl.ts
+++ b/src/vs/workbench/api/common/extHost.api.impl.ts
@@ -457,9 +457,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerCodeActionsProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider, metadata?: vscode.CodeActionProviderMetadata): vscode.Disposable {
return extHostLanguageFeatures.registerCodeActionProvider(extension, checkSelector(selector), provider, metadata);
},
- registerDocumentPasteEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider): vscode.Disposable {
+ registerDocumentPasteEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider, metadata: vscode.DocumentPasteProviderMetadata): vscode.Disposable {
checkProposedApiEnabled(extension, 'documentPaste');
- return extHostLanguageFeatures.registerDocumentPasteEditProvider(extension, checkSelector(selector), provider);
+ return extHostLanguageFeatures.registerDocumentPasteEditProvider(extension, checkSelector(selector), provider, metadata);
},
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
return extHostLanguageFeatures.registerCodeLensProvider(extension, checkSelector(selector), provider);
@@ -1267,7 +1267,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
SignatureHelpTriggerKind: extHostTypes.SignatureHelpTriggerKind,
SignatureInformation: extHostTypes.SignatureInformation,
SnippetString: extHostTypes.SnippetString,
- SnippetTextEdit: extHostTypes.SnippetTextEdit,
SourceBreakpoint: extHostTypes.SourceBreakpoint,
StandardTokenType: extHostTypes.StandardTokenType,
StatusBarAlignment: extHostTypes.StatusBarAlignment,
diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts
index 865a0e5c4eb..60478d4a194 100644
--- a/src/vs/workbench/api/common/extHost.protocol.ts
+++ b/src/vs/workbench/api/common/extHost.protocol.ts
@@ -372,7 +372,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
$registerLinkedEditingRangeProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void;
$registerQuickFixSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto, displayName: string, supportsResolve: boolean): void;
- $registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean): void;
+ $registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean, pasteMimeTypes: readonly string[]): void;
$registerDocumentFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void;
$registerRangeFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void;
$registerOnTypeFormattingSupport(handle: number, selector: IDocumentFilterDto[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void;
@@ -1713,6 +1713,16 @@ export interface IInlineValueContextDto {
export type ITypeHierarchyItemDto = Dto<TypeHierarchyItem>;
+export interface IPasteEditDto {
+ insertText: string | { snippet: string };
+ additionalEdit?: IWorkspaceEditDto;
+}
+
+export interface IDocumentOnDropEditDto {
+ insertText: string | { snippet: string };
+ additionalEdit?: IWorkspaceEditDto;
+}
+
export interface ExtHostLanguageFeaturesShape {
$provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise<languages.DocumentSymbol[] | undefined>;
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<ICodeLensListDto | undefined>;
@@ -1731,8 +1741,8 @@ export interface ExtHostLanguageFeaturesShape {
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: languages.CodeActionContext, token: CancellationToken): Promise<ICodeActionListDto | undefined>;
$resolveCodeAction(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<IWorkspaceEditDto | undefined>;
$releaseCodeActions(handle: number, cacheId: number): void;
- $prepareDocumentPaste(handle: number, uri: UriComponents, range: IRange, dataTransfer: DataTransferDTO, token: CancellationToken): Promise<DataTransferDTO | undefined>;
- $providePasteEdits(handle: number, uri: UriComponents, range: IRange, dataTransfer: DataTransferDTO, token: CancellationToken): Promise<IWorkspaceEditDto | Dto<languages.SnippetTextEdit> | undefined>;
+ $prepareDocumentPaste(handle: number, uri: UriComponents, ranges: IRange[], dataTransfer: DataTransferDTO, token: CancellationToken): Promise<DataTransferDTO | undefined>;
+ $providePasteEdits(handle: number, uri: UriComponents, ranges: IRange[], dataTransfer: DataTransferDTO, token: CancellationToken): Promise<IPasteEditDto | undefined>;
$provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: languages.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined>;
$provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: languages.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined>;
$provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: languages.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined>;
@@ -1771,7 +1781,7 @@ export interface ExtHostLanguageFeaturesShape {
$provideTypeHierarchySupertypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<ITypeHierarchyItemDto[] | undefined>;
$provideTypeHierarchySubtypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<ITypeHierarchyItemDto[] | undefined>;
$releaseTypeHierarchy(handle: number, sessionId: string): void;
- $provideDocumentOnDropEdits(handle: number, requestId: number, resource: UriComponents, position: IPosition, dataTransferDto: DataTransferDTO, token: CancellationToken): Promise<Dto<languages.SnippetTextEdit> | undefined>;
+ $provideDocumentOnDropEdits(handle: number, requestId: number, resource: UriComponents, position: IPosition, dataTransferDto: DataTransferDTO, token: CancellationToken): Promise<IDocumentOnDropEditDto | undefined>;
}
export interface ExtHostQuickOpenShape {
diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts
index 040e4dffe64..7608468e560 100644
--- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts
+++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts
@@ -7,7 +7,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { mixin } from 'vs/base/common/objects';
import type * as vscode from 'vscode';
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
-import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit, Location, InlineCompletionTriggerKindNew, InlineCompletionTriggerKind, WorkspaceEdit } from 'vs/workbench/api/common/extHostTypes';
+import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit, Location, InlineCompletionTriggerKindNew, InlineCompletionTriggerKind } from 'vs/workbench/api/common/extHostTypes';
import { ISingleEditOperation } from 'vs/editor/common/core/editOperation';
import * as languages from 'vs/editor/common/languages';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
@@ -34,7 +34,6 @@ import { StopWatch } from 'vs/base/common/stopwatch';
import { isCancellationError, NotImplementedError } from 'vs/base/common/errors';
import { raceCancellationError } from 'vs/base/common/async';
import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
-import { Dto } from 'vs/workbench/services/extensions/common/proxyIdentifier';
// --- adapter
@@ -494,40 +493,39 @@ class DocumentPasteEditProvider {
private readonly _handle: number,
) { }
- async prepareDocumentPaste(resource: URI, range: IRange, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.DataTransferDTO | undefined> {
+ async prepareDocumentPaste(resource: URI, ranges: IRange[], dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.DataTransferDTO | undefined> {
if (!this._provider.prepareDocumentPaste) {
return undefined;
}
const doc = this._documents.getDocument(resource);
- const vscodeRange = typeConvert.Range.to(range);
+ const vscodeRanges = ranges.map(range => typeConvert.Range.to(range));
const dataTransfer = typeConvert.DataTransfer.toDataTransfer(dataTransferDto, () => {
throw new NotImplementedError();
});
- await this._provider.prepareDocumentPaste(doc, vscodeRange, dataTransfer, token);
+ await this._provider.prepareDocumentPaste(doc, vscodeRanges, dataTransfer, token);
return typeConvert.DataTransfer.toDataTransferDTO(dataTransfer);
}
- async providePasteEdits(requestId: number, resource: URI, range: IRange, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<undefined | extHostProtocol.IWorkspaceEditDto | Dto<languages.SnippetTextEdit>> {
+ async providePasteEdits(requestId: number, resource: URI, ranges: IRange[], dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<undefined | extHostProtocol.IPasteEditDto> {
const doc = this._documents.getDocument(resource);
- const vscodeRange = typeConvert.Range.to(range);
+ const vscodeRanges = ranges.map(range => typeConvert.Range.to(range));
const dataTransfer = typeConvert.DataTransfer.toDataTransfer(dataTransferDto, async (index) => {
return (await this._proxy.$resolveDocumentOnDropFileData(this._handle, requestId, index)).buffer;
});
- const edit = await this._provider.provideDocumentPasteEdits(doc, vscodeRange, dataTransfer, token);
+ const edit = await this._provider.provideDocumentPasteEdits(doc, vscodeRanges, dataTransfer, token);
if (!edit) {
return;
}
- if (edit instanceof WorkspaceEdit) {
- return typeConvert.WorkspaceEdit.from(edit);
- } else {
- return typeConvert.SnippetTextEdit.from(edit as vscode.SnippetTextEdit);
- }
+ return {
+ insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value },
+ additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit) : undefined,
+ };
}
}
@@ -1799,7 +1797,7 @@ class DocumentOnDropEditAdapter {
private readonly _handle: number,
) { }
- async provideDocumentOnDropEdits(requestId: number, uri: URI, position: IPosition, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<Dto<languages.SnippetTextEdit> | undefined> {
+ async provideDocumentOnDropEdits(requestId: number, uri: URI, position: IPosition, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.IDocumentOnDropEditDto | undefined> {
const doc = this._documents.getDocument(uri);
const pos = typeConvert.Position.to(position);
const dataTransfer = typeConvert.DataTransfer.toDataTransfer(dataTransferDto, async (index) => {
@@ -1810,7 +1808,10 @@ class DocumentOnDropEditAdapter {
if (!edit) {
return undefined;
}
- return typeConvert.SnippetTextEdit.from(edit);
+ return {
+ insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value },
+ additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit) : undefined,
+ };
}
}
@@ -2454,26 +2455,26 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
return this._createDisposable(handle);
}
- $provideDocumentOnDropEdits(handle: number, requestId: number, resource: UriComponents, position: IPosition, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<Dto<languages.SnippetTextEdit> | undefined> {
+ $provideDocumentOnDropEdits(handle: number, requestId: number, resource: UriComponents, position: IPosition, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.IDocumentOnDropEditDto | undefined> {
return this._withAdapter(handle, DocumentOnDropEditAdapter, adapter =>
Promise.resolve(adapter.provideDocumentOnDropEdits(requestId, URI.revive(resource), position, dataTransferDto, token)), undefined, undefined);
}
// --- copy/paste actions
- registerDocumentPasteEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider): vscode.Disposable {
+ registerDocumentPasteEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider, metadata: vscode.DocumentPasteProviderMetadata): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new AdapterData(new DocumentPasteEditProvider(this._proxy, this._documents, provider, handle), extension));
- this._proxy.$registerPasteEditProvider(handle, this._transformDocumentSelector(selector), !!provider.prepareDocumentPaste);
+ this._proxy.$registerPasteEditProvider(handle, this._transformDocumentSelector(selector), !!provider.prepareDocumentPaste, metadata.pasteMimeTypes);
return this._createDisposable(handle);
}
- $prepareDocumentPaste(handle: number, resource: UriComponents, range: IRange, dataTransfer: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.DataTransferDTO | undefined> {
- return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.prepareDocumentPaste(URI.revive(resource), range, dataTransfer, token), undefined, token);
+ $prepareDocumentPaste(handle: number, resource: UriComponents, ranges: IRange[], dataTransfer: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.DataTransferDTO | undefined> {
+ return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.prepareDocumentPaste(URI.revive(resource), ranges, dataTransfer, token), undefined, token);
}
- $providePasteEdits(handle: number, resource: UriComponents, range: IRange, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.IWorkspaceEditDto | Dto<languages.SnippetTextEdit> | undefined> {
- return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.providePasteEdits(0, URI.revive(resource), range, dataTransferDto, token), undefined, token);
+ $providePasteEdits(handle: number, resource: UriComponents, ranges: IRange[], dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.IPasteEditDto | undefined> {
+ return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.providePasteEdits(0, URI.revive(resource), ranges, dataTransferDto, token), undefined, token);
}
// --- configuration
diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts
index dcacff191cf..5bf0397e70b 100644
--- a/src/vs/workbench/api/common/extHostTypeConverters.ts
+++ b/src/vs/workbench/api/common/extHostTypeConverters.ts
@@ -562,15 +562,6 @@ export namespace TextEdit {
}
}
-export namespace SnippetTextEdit {
- export function from(edit: vscode.SnippetTextEdit): languages.SnippetTextEdit {
- return {
- range: Range.from(edit.range),
- snippet: edit.snippet.value
- };
- }
-}
-
export namespace WorkspaceEdit {
export interface IVersionInformationProvider {
diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts
index 467bcc523c1..e3bdbf13e03 100644
--- a/src/vs/workbench/api/common/extHostTypes.ts
+++ b/src/vs/workbench/api/common/extHostTypes.ts
@@ -647,17 +647,6 @@ export class NotebookEdit implements vscode.NotebookEdit {
}
}
-export class SnippetTextEdit implements vscode.SnippetTextEdit {
-
- range: vscode.Range;
- snippet: vscode.SnippetString;
-
- constructor(range: Range, snippet: SnippetString) {
- this.range = range;
- this.snippet = snippet;
- }
-}
-
export interface IFileOperationOptions {
overwrite?: boolean;
ignoreIfExists?: boolean;
diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts
index d8cea442776..6343fd24e4f 100644
--- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts
+++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts
@@ -23,7 +23,7 @@ import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor
import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor';
import { ChangeEncodingAction, ChangeEOLAction, ChangeLanguageAction, EditorStatus } from 'vs/workbench/browser/parts/editor/editorStatus';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions, CATEGORIES } from 'vs/workbench/common/actions';
-import { SyncActionDescriptor, MenuRegistry, MenuId, IMenuItem } from 'vs/platform/actions/common/actions';
+import { SyncActionDescriptor, MenuRegistry, MenuId, IMenuItem, registerAction2 } from 'vs/platform/actions/common/actions';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import {
@@ -244,8 +244,6 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupLeftAct
registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupRightAction), 'View: New Editor Group to the Right', CATEGORIES.View.value);
registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupAboveAction), 'View: New Editor Group Above', CATEGORIES.View.value);
registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupBelowAction), 'View: New Editor Group Below', CATEGORIES.View.value);
-registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateForwardAction, { primary: 0, win: { primary: KeyMod.Alt | KeyCode.RightArrow }, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Minus }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Minus } }), 'Go Forward');
-registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateBackwardsAction, { primary: 0, win: { primary: KeyMod.Alt | KeyCode.LeftArrow }, mac: { primary: KeyMod.WinCtrl | KeyCode.Minus }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Minus } }), 'Go Back');
registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigatePreviousAction), 'Go Previous');
registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateForwardInEditsAction), 'Go Forward in Edit Locations');
registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateBackwardsInEditsAction), 'Go Back in Edit Locations');
@@ -273,6 +271,9 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessPreviousRe
registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessLeastRecentlyUsedEditorInGroupAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab } }, ActiveEditorGroupEmptyContext.toNegated()), 'View: Quick Open Least Recently Used Editor in Group', CATEGORIES.View.value);
registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessPreviousEditorFromHistoryAction), 'Quick Open Previous Editor from History');
+registerAction2(NavigateForwardAction);
+registerAction2(NavigateBackwardsAction);
+
const quickAccessNavigateNextInEditorPickerId = 'workbench.action.quickOpenNavigateNextInEditorPicker';
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: quickAccessNavigateNextInEditorPickerId,
@@ -314,9 +315,6 @@ if (isMacintosh) {
});
}
-MenuRegistry.appendMenuItem(MenuId.CommandCenter, { order: 1, command: { id: NavigateBackwardsAction.ID, title: NavigateBackwardsAction.LABEL, icon: Codicon.arrowLeft } });
-MenuRegistry.appendMenuItem(MenuId.CommandCenter, { order: 2, command: { id: NavigateForwardAction.ID, title: NavigateForwardAction.LABEL, icon: Codicon.arrowRight } });
-
// Empty Editor Group Toolbar
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroup, { command: { id: UNLOCK_GROUP_COMMAND_ID, title: localize('unlockGroupAction', "Unlock Group"), icon: Codicon.lock }, group: 'navigation', order: 10, when: ActiveEditorGroupLockedContext });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroup, { command: { id: CLOSE_EDITOR_GROUP_COMMAND_ID, title: localize('closeGroupAction', "Close Group"), icon: Codicon.close }, group: 'navigation', order: 20 });
@@ -775,27 +773,6 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
// Main Menu Bar Contributions:
-// Forward/Back
-MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
- group: '1_history_nav',
- command: {
- id: 'workbench.action.navigateBack',
- title: localize({ key: 'miBack', comment: ['&& denotes a mnemonic'] }, "&&Back"),
- precondition: ContextKeyExpr.has('canNavigateBack')
- },
- order: 1
-});
-
-MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
- group: '1_history_nav',
- command: {
- id: 'workbench.action.navigateForward',
- title: localize({ key: 'miForward', comment: ['&& denotes a mnemonic'] }, "&&Forward"),
- precondition: ContextKeyExpr.has('canNavigateForward')
- },
- order: 2
-});
-
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
group: '1_history_nav',
command: {
diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts
index a993829e847..bf39a77a241 100644
--- a/src/vs/workbench/browser/parts/editor/editorActions.ts
+++ b/src/vs/workbench/browser/parts/editor/editorActions.ts
@@ -26,6 +26,11 @@ import { Codicon } from 'vs/base/common/codicons';
import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { IEditorResolverService } from 'vs/workbench/services/editor/common/editorResolverService';
import { isLinux, isNative, isWindows } from 'vs/base/common/platform';
+import { Action2, MenuId } from 'vs/platform/actions/common/actions';
+import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
+import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
+import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
+import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
export class ExecuteCommandAction extends Action {
@@ -1258,39 +1263,67 @@ export class OpenLastEditorInGroup extends AbstractNavigateEditorAction {
}
}
-export class NavigateForwardAction extends Action {
+export class NavigateForwardAction extends Action2 {
static readonly ID = 'workbench.action.navigateForward';
static readonly LABEL = localize('navigateForward', "Go Forward");
- constructor(
- id: string,
- label: string,
- @IHistoryService private readonly historyService: IHistoryService
- ) {
- super(id, label);
+ constructor() {
+ super({
+ id: NavigateForwardAction.ID,
+ title: { value: localize('navigateForward', "Go Forward"), original: 'Go Forward', mnemonicTitle: localize({ key: 'miForward', comment: ['&& denotes a mnemonic'] }, "&&Forward") },
+ f1: true,
+ icon: Codicon.arrowRight,
+ precondition: ContextKeyExpr.has('canNavigateForward'),
+ keybinding: {
+ weight: KeybindingWeight.WorkbenchContrib,
+ win: { primary: KeyMod.Alt | KeyCode.RightArrow },
+ mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Minus },
+ linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Minus }
+ },
+ menu: [
+ { id: MenuId.MenubarGoMenu, group: '1_history_nav', order: 2 },
+ { id: MenuId.CommandCenter, order: 2 }
+ ]
+ });
}
- override async run(): Promise<void> {
- await this.historyService.goForward(GoFilter.NONE);
+ async run(accessor: ServicesAccessor): Promise<void> {
+ const historyService = accessor.get(IHistoryService);
+
+ await historyService.goForward(GoFilter.NONE);
}
}
-export class NavigateBackwardsAction extends Action {
+export class NavigateBackwardsAction extends Action2 {
static readonly ID = 'workbench.action.navigateBack';
static readonly LABEL = localize('navigateBack', "Go Back");
- constructor(
- id: string,
- label: string,
- @IHistoryService private readonly historyService: IHistoryService
- ) {
- super(id, label);
+ constructor() {
+ super({
+ id: NavigateBackwardsAction.ID,
+ title: { value: localize('navigateBack', "Go Back"), original: 'Go Back', mnemonicTitle: localize({ key: 'miBack', comment: ['&& denotes a mnemonic'] }, "&&Back") },
+ f1: true,
+ precondition: ContextKeyExpr.has('canNavigateBack'),
+ icon: Codicon.arrowLeft,
+ keybinding: {
+ weight: KeybindingWeight.WorkbenchContrib,
+ win: { primary: KeyMod.Alt | KeyCode.LeftArrow },
+ mac: { primary: KeyMod.WinCtrl | KeyCode.Minus },
+ linux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Minus }
+ },
+ menu: [
+ { id: MenuId.MenubarGoMenu, group: '1_history_nav', order: 1 },
+ { id: MenuId.CommandCenter, order: 1 }
+ ]
+ });
}
- override async run(): Promise<void> {
- await this.historyService.goBack(GoFilter.NONE);
+ async run(accessor: ServicesAccessor): Promise<void> {
+ const historyService = accessor.get(IHistoryService);
+
+ await historyService.goBack(GoFilter.NONE);
}
}
diff --git a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts
index b6e9f118b66..af98c5ae2c8 100644
--- a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts
+++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts
@@ -597,6 +597,7 @@ export class EditorDropTarget extends Themable {
private registerListeners(): void {
this._register(addDisposableListener(this.container, EventType.DRAG_ENTER, e => this.onDragEnter(e)));
this._register(addDisposableListener(this.container, EventType.DRAG_LEAVE, () => this.onDragLeave()));
+ this._register(addDisposableListener(this.container, EventType.DRAG_OVER, e => this.onDragEnter(e)));
[this.container, window].forEach(node => this._register(addDisposableListener(node as HTMLElement, EventType.DRAG_END, () => this.onDragEnd())));
}
diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts
index 50c7f78b6b2..398674d57aa 100644
--- a/src/vs/workbench/contrib/debug/browser/debugService.ts
+++ b/src/vs/workbench/contrib/debug/browser/debugService.ts
@@ -690,8 +690,11 @@ export class DebugService implements IDebugService {
const dataBreakpoints = this.model.getDataBreakpoints().filter(dbp => !dbp.canPersist);
dataBreakpoints.forEach(dbp => this.model.removeDataBreakpoints(dbp.getId()));
- if (this.viewsService.isViewVisible(REPL_VIEW_ID) && this.configurationService.getValue<IDebugConfiguration>('debug').console.closeOnEnd) {
- this.viewsService.closeView(REPL_VIEW_ID);
+ if (this.configurationService.getValue<IDebugConfiguration>('debug').console.closeOnEnd) {
+ const debugConsoleContainer = this.viewDescriptorService.getViewContainerByViewId(REPL_VIEW_ID);
+ if (debugConsoleContainer && this.viewsService.isViewContainerVisible(debugConsoleContainer.id)) {
+ this.viewsService.closeViewContainer(debugConsoleContainer.id);
+ }
}
}
}));
diff --git a/src/vs/workbench/contrib/debug/browser/variablesView.ts b/src/vs/workbench/contrib/debug/browser/variablesView.ts
index 01aac2fa0b6..d4e995fb9f1 100644
--- a/src/vs/workbench/contrib/debug/browser/variablesView.ts
+++ b/src/vs/workbench/contrib/debug/browser/variablesView.ts
@@ -96,10 +96,10 @@ export class VariablesView extends ViewPane {
const viewState = this.savedViewState.get(stackFrame.getId());
await this.tree.setInput(stackFrame, viewState);
- // Automatically expand the first scope if it is not expensive and if all scopes are collapsed
+ // Automatically expand the first non-expensive scope
const scopes = await stackFrame.getScopes();
const toExpand = scopes.find(s => !s.expensive);
- if (toExpand && (scopes.every(s => this.tree.isCollapsed(s)) || !this.autoExpandedScopes.has(toExpand.getId()))) {
+ if (toExpand) {
this.autoExpandedScopes.add(toExpand.getId());
await this.tree.expand(toExpand);
}
diff --git a/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts
index c05fc04c956..4b20e069cd2 100644
--- a/src/vs/workbench/contrib/debug/common/debugModel.ts
+++ b/src/vs/workbench/contrib/debug/common/debugModel.ts
@@ -7,6 +7,7 @@ import { distinct, lastIndex } from 'vs/base/common/arrays';
import { RunOnceScheduler } from 'vs/base/common/async';
import { decodeBase64, encodeBase64, VSBuffer } from 'vs/base/common/buffer';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
+import { stringHash } from 'vs/base/common/hash';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { mixin } from 'vs/base/common/objects';
@@ -351,7 +352,7 @@ export class Scope extends ExpressionContainer implements IScope {
constructor(
stackFrame: IStackFrame,
- index: number,
+ id: number,
public readonly name: string,
reference: number,
public expensive: boolean,
@@ -359,7 +360,7 @@ export class Scope extends ExpressionContainer implements IScope {
indexedVariables?: number,
public readonly range?: IRange
) {
- super(stackFrame.thread.session, stackFrame.thread.threadId, reference, `scope:${name}:${index}`, namedVariables, indexedVariables);
+ super(stackFrame.thread.session, stackFrame.thread.threadId, reference, `scope:${name}:${id}`, namedVariables, indexedVariables);
}
override toString(): string {
@@ -417,12 +418,17 @@ export class StackFrame implements IStackFrame {
return [];
}
- const scopeNameIndexes = new Map<string, number>();
+ const usedIds = new Set<number>();
return response.body.scopes.map(rs => {
- const previousIndex = scopeNameIndexes.get(rs.name);
- const index = typeof previousIndex === 'number' ? previousIndex + 1 : 0;
- scopeNameIndexes.set(rs.name, index);
- return new Scope(this, index, rs.name, rs.variablesReference, rs.expensive, rs.namedVariables, rs.indexedVariables,
+ // form the id based on the name and location so that it's the
+ // same across multiple pauses to retain expansion state
+ let id = 0;
+ do {
+ id = stringHash(`${rs.name}:${rs.line}:${rs.column}`, id);
+ } while (usedIds.has(id));
+
+ usedIds.add(id);
+ return new Scope(this, id, rs.name, rs.variablesReference, rs.expensive, rs.namedVariables, rs.indexedVariables,
rs.line && rs.column && rs.endLine && rs.endColumn ? new Range(rs.line, rs.column, rs.endLine, rs.endColumn) : undefined);
});
diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts
index 48bf5fb81e3..8fa3b9b8f93 100644
--- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts
+++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts
@@ -16,13 +16,13 @@ import { append, $, finalHandler, join, addDisposableListener, EventType, setPar
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
-import { IExtensionIgnoredRecommendationsService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
+import { IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
import { IExtensionManifest, IKeyBinding, IView, IViewContainer } from 'vs/platform/extensions/common/extensions';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { ResolvedKeybinding } from 'vs/base/common/keybindings';
import { ExtensionsInput, IExtensionEditorOptions } from 'vs/workbench/contrib/extensions/common/extensionsInput';
-import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, IExtension, ExtensionContainers, ExtensionEditorTab, ExtensionState } from 'vs/workbench/contrib/extensions/common/extensions';
-import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget, ExtensionWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
+import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, IExtension, ExtensionContainers, ExtensionEditorTab, ExtensionState, IExtensionContainer } from 'vs/workbench/contrib/extensions/common/extensions';
+import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget, ExtensionWidget, ExtensionStatusWidget, ExtensionRecommendationWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
import { IEditorOpenContext } from 'vs/workbench/common/editor';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import {
@@ -66,8 +66,7 @@ import { Delegate } from 'vs/workbench/contrib/extensions/browser/extensionsList
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
import { attachKeybindingLabelStyler } from 'vs/platform/theme/common/styler';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
-import { errorIcon, infoIcon, preReleaseIcon, starEmptyIcon, verifiedPublisherIcon as verifiedPublisherThemeIcon, warningIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
-import { MarkdownString } from 'vs/base/common/htmlContent';
+import { errorIcon, infoIcon, preReleaseIcon, verifiedPublisherIcon as verifiedPublisherThemeIcon, warningIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
import { ViewContainerLocation } from 'vs/workbench/common/views';
import { IExtensionGalleryService, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
@@ -147,8 +146,6 @@ interface IExtensionEditorTemplate {
description: HTMLElement;
actionsAndStatusContainer: HTMLElement;
extensionActionBar: ActionBar;
- status: HTMLElement;
- recommendation: HTMLElement;
navbar: NavBar;
content: HTMLElement;
header: HTMLElement;
@@ -251,7 +248,6 @@ export class ExtensionEditor extends EditorPane {
@INotificationService private readonly notificationService: INotificationService,
@IOpenerService private readonly openerService: IOpenerService,
@IExtensionRecommendationsService private readonly extensionRecommendationsService: IExtensionRecommendationsService,
- @IExtensionIgnoredRecommendationsService private readonly extensionIgnoredRecommendationsService: IExtensionIgnoredRecommendationsService,
@IStorageService storageService: IStorageService,
@IExtensionService private readonly extensionService: IExtensionService,
@IWebviewService private readonly webviewService: IWebviewService,
@@ -310,7 +306,7 @@ export class ExtensionEditor extends EditorPane {
rating.setAttribute('role', 'link'); // #132645
const ratingsWidget = this.instantiationService.createInstance(RatingsWidget, rating, false);
- const widgets = [
+ const widgets: ExtensionWidget[] = [
remoteBadge,
versionWidget,
preReleaseWidget,
@@ -375,14 +371,30 @@ export class ExtensionEditor extends EditorPane {
extensionActionBar.setFocusable(true);
}));
- const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]);
- for (const disposable of [...actions, ...widgets, extensionContainers]) {
+ const otherExtensionContainers: IExtensionContainer[] = [];
+ const extensionStatusAction = this.instantiationService.createInstance(ExtensionStatusAction);
+ const extensionStatusWidget = this._register(this.instantiationService.createInstance(ExtensionStatusWidget, append(actionsAndStatusContainer, $('.status')), extensionStatusAction));
+
+ otherExtensionContainers.push(extensionStatusAction, new class extends ExtensionWidget {
+ render() {
+ actionsAndStatusContainer.classList.toggle('list-layout', this.extension?.state === ExtensionState.Installed);
+ }
+ }());
+
+ const recommendationWidget = this.instantiationService.createInstance(ExtensionRecommendationWidget, append(details, $('.recommendation')));
+ widgets.push(recommendationWidget);
+
+ this._register(Event.any(extensionStatusWidget.onDidRender, recommendationWidget.onDidRender)(() => {
+ if (this.dimension) {
+ this.layout(this.dimension);
+ }
+ }));
+
+ const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets, ...otherExtensionContainers]);
+ for (const disposable of [...actions, ...widgets, ...otherExtensionContainers, extensionContainers]) {
this._register(disposable);
}
- const status = append(actionsAndStatusContainer, $('.status'));
- const recommendation = append(details, $('.recommendation'));
-
this._register(Event.chain(extensionActionBar.onDidRun)
.map(({ error }) => error)
.filter(error => !!error)
@@ -411,8 +423,6 @@ export class ExtensionEditor extends EditorPane {
rating,
actionsAndStatusContainer,
extensionActionBar,
- status,
- recommendation,
set extension(extension: IExtension) {
extensionContainers.extension = extension;
},
@@ -544,9 +554,6 @@ export class ExtensionEditor extends EditorPane {
}));
}
- this.setStatus(extension, template);
- this.setRecommendationText(extension, template);
-
const manifest = await this.extensionManifest.get().promise;
if (token.isCancellationRequested) {
return;
@@ -620,72 +627,6 @@ export class ExtensionEditor extends EditorPane {
template.navbar.onChange(e => this.onNavbarChange(extension, e, template), this, this.transientDisposables);
}
- private setStatus(extension: IExtension, template: IExtensionEditorTemplate): void {
- const disposables = this.transientDisposables.add(new DisposableStore());
- const extensionStatus = disposables.add(this.instantiationService.createInstance(ExtensionStatusAction));
- extensionStatus.extension = extension;
- const updateStatus = (layout: boolean) => {
- disposables.clear();
- reset(template.status);
- const status = extensionStatus.status;
- if (status) {
- if (status.icon) {
- const statusIconActionBar = disposables.add(new ActionBar(template.status, { animated: false }));
- statusIconActionBar.push(extensionStatus, { icon: true, label: false });
- }
- disposables.add(this.renderMarkdownText(status.message.value, append(template.status, $('.status-text'))));
- }
- if (layout && this.dimension) {
- this.layout(this.dimension);
- }
- };
- updateStatus(false);
- this.transientDisposables.add(extensionStatus.onDidChangeStatus(() => updateStatus(true)));
-
- const updateActionLayout = () => template.actionsAndStatusContainer.classList.toggle('list-layout', extension.state === ExtensionState.Installed);
- updateActionLayout();
- this.transientDisposables.add(this.extensionsWorkbenchService.onChange(() => updateActionLayout()));
- }
-
- private setRecommendationText(extension: IExtension, template: IExtensionEditorTemplate): void {
- const updateRecommendationText = (layout: boolean) => {
- reset(template.recommendation);
- const extRecommendations = this.extensionRecommendationsService.getAllRecommendationsWithReason();
- if (extRecommendations[extension.identifier.id.toLowerCase()]) {
- const reasonText = extRecommendations[extension.identifier.id.toLowerCase()].reasonText;
- if (reasonText) {
- append(template.recommendation, $(`div${ThemeIcon.asCSSSelector(starEmptyIcon)}`));
- append(template.recommendation, $(`div.recommendation-text`, undefined, reasonText));
- }
- } else if (this.extensionIgnoredRecommendationsService.globalIgnoredRecommendations.indexOf(extension.identifier.id.toLowerCase()) !== -1) {
- append(template.recommendation, $(`div.recommendation-text`, undefined, localize('recommendationHasBeenIgnored', "You have chosen not to receive recommendations for this extension.")));
- }
- if (layout && this.dimension) {
- this.layout(this.dimension);
- }
- };
- if (extension.deprecationInfo || extension.state === ExtensionState.Installed) {
- reset(template.recommendation);
- return;
- }
- updateRecommendationText(false);
- this.transientDisposables.add(this.extensionRecommendationsService.onDidChangeRecommendations(() => updateRecommendationText(true)));
- }
-
- private renderMarkdownText(markdownText: string, parent: HTMLElement): IDisposable {
- const disposables = new DisposableStore();
- const rendered = disposables.add(renderMarkdown(new MarkdownString(markdownText, { isTrusted: true, supportThemeIcons: true }), {
- actionHandler: {
- callback: (content) => {
- this.openerService.open(content, { allowCommands: true }).catch(onUnexpectedError);
- },
- disposables: disposables
- }
- }));
- append(parent, rendered.element);
- return disposables;
- }
-
override clearInput(): void {
this.contentDisposables.clear();
this.transientDisposables.clear();
diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
index b339a649e84..cba60a0ef88 100644
--- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
+++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
@@ -2944,6 +2944,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
const errorColor = theme.getColor(editorErrorForeground);
if (errorColor) {
collector.addRule(`.monaco-action-bar .action-item .action-label.extension-action.extension-status-error { color: ${errorColor}; }`);
+ collector.addRule(`.extension-editor .header .actions-status-container > .status ${ThemeIcon.asCSSSelector(errorIcon)} { color: ${errorColor}; }`);
collector.addRule(`.extension-editor .body .subcontent .runtime-status ${ThemeIcon.asCSSSelector(errorIcon)} { color: ${errorColor}; }`);
collector.addRule(`.monaco-hover.extension-hover .markdown-hover .hover-contents ${ThemeIcon.asCSSSelector(errorIcon)} { color: ${errorColor}; }`);
}
@@ -2951,6 +2952,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
const warningColor = theme.getColor(editorWarningForeground);
if (warningColor) {
collector.addRule(`.monaco-action-bar .action-item .action-label.extension-action.extension-status-warning { color: ${warningColor}; }`);
+ collector.addRule(`.extension-editor .header .actions-status-container > .status ${ThemeIcon.asCSSSelector(warningIcon)} { color: ${warningColor}; }`);
collector.addRule(`.extension-editor .body .subcontent .runtime-status ${ThemeIcon.asCSSSelector(warningIcon)} { color: ${warningColor}; }`);
collector.addRule(`.monaco-hover.extension-hover .markdown-hover .hover-contents ${ThemeIcon.asCSSSelector(warningIcon)} { color: ${warningColor}; }`);
}
@@ -2958,6 +2960,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
const infoColor = theme.getColor(editorInfoForeground);
if (infoColor) {
collector.addRule(`.monaco-action-bar .action-item .action-label.extension-action.extension-status-info { color: ${infoColor}; }`);
+ collector.addRule(`.extension-editor .header .actions-status-container > .status ${ThemeIcon.asCSSSelector(infoIcon)} { color: ${infoColor}; }`);
collector.addRule(`.extension-editor .body .subcontent .runtime-status ${ThemeIcon.asCSSSelector(infoIcon)} { color: ${infoColor}; }`);
collector.addRule(`.monaco-hover.extension-hover .markdown-hover .hover-contents ${ThemeIcon.asCSSSelector(infoIcon)} { color: ${infoColor}; }`);
}
diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts
index 1760db32044..ef58205dfb2 100644
--- a/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts
+++ b/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts
@@ -7,16 +7,16 @@ import 'vs/css!./media/extensionsWidgets';
import * as semver from 'vs/base/common/semver/semver';
import { Disposable, toDisposable, DisposableStore, MutableDisposable, IDisposable } from 'vs/base/common/lifecycle';
import { IExtension, IExtensionsWorkbenchService, IExtensionContainer, ExtensionState, ExtensionEditorTab } from 'vs/workbench/contrib/extensions/common/extensions';
-import { append, $ } from 'vs/base/browser/dom';
+import { append, $, reset } from 'vs/base/browser/dom';
import * as platform from 'vs/base/common/platform';
import { localize } from 'vs/nls';
import { EnablementState, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
-import { IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
+import { IExtensionIgnoredRecommendationsService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
import { ILabelService } from 'vs/platform/label/common/label';
import { extensionButtonProminentBackground, extensionButtonProminentForeground, ExtensionStatusAction, ReloadAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { IThemeService, ThemeIcon, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { EXTENSION_BADGE_REMOTE_BACKGROUND, EXTENSION_BADGE_REMOTE_FOREGROUND } from 'vs/workbench/common/theme';
-import { Event } from 'vs/base/common/event';
+import { Emitter, Event } from 'vs/base/common/event';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -32,6 +32,9 @@ import { areSameExtensions } from 'vs/platform/extensionManagement/common/extens
import Severity from 'vs/base/common/severity';
import { setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';
import { Color } from 'vs/base/common/color';
+import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
+import { IOpenerService } from 'vs/platform/opener/common/opener';
+import { onUnexpectedError } from 'vs/base/common/errors';
export abstract class ExtensionWidget extends Disposable implements IExtensionContainer {
private _extension: IExtension | null = null;
@@ -576,6 +579,93 @@ export class ExtensionHoverWidget extends ExtensionWidget {
}
+export class ExtensionStatusWidget extends ExtensionWidget {
+
+ private readonly renderDisposables = this._register(new DisposableStore());
+
+ private readonly _onDidRender = this._register(new Emitter<void>());
+ readonly onDidRender: Event<void> = this._onDidRender.event;
+
+ constructor(
+ private readonly container: HTMLElement,
+ private readonly extensionStatusAction: ExtensionStatusAction,
+ @IOpenerService private readonly openerService: IOpenerService,
+ ) {
+ super();
+ this.render();
+ this._register(extensionStatusAction.onDidChangeStatus(() => this.render()));
+ }
+
+ render(): void {
+ reset(this.container);
+ const extensionStatus = this.extensionStatusAction.status;
+ if (extensionStatus) {
+ const markdown = new MarkdownString('', { isTrusted: true, supportThemeIcons: true });
+ if (extensionStatus.icon) {
+ markdown.appendMarkdown(`$(${extensionStatus.icon.id})&nbsp;`);
+ }
+ markdown.appendMarkdown(extensionStatus.message.value);
+ const rendered = this.renderDisposables.add(renderMarkdown(markdown, {
+ actionHandler: {
+ callback: (content) => {
+ this.openerService.open(content, { allowCommands: true }).catch(onUnexpectedError);
+ },
+ disposables: this.renderDisposables
+ }
+ }));
+ append(this.container, rendered.element);
+ }
+ this._onDidRender.fire();
+ }
+}
+
+export class ExtensionRecommendationWidget extends ExtensionWidget {
+
+ private readonly _onDidRender = this._register(new Emitter<void>());
+ readonly onDidRender: Event<void> = this._onDidRender.event;
+
+ constructor(
+ private readonly container: HTMLElement,
+ @IExtensionRecommendationsService private readonly extensionRecommendationsService: IExtensionRecommendationsService,
+ @IExtensionIgnoredRecommendationsService private readonly extensionIgnoredRecommendationsService: IExtensionIgnoredRecommendationsService,
+ ) {
+ super();
+ this.render();
+ this._register(this.extensionRecommendationsService.onDidChangeRecommendations(() => this.render()));
+ }
+
+ render(): void {
+ reset(this.container);
+ const recommendationStatus = this.getRecommendationStatus();
+ if (recommendationStatus) {
+ if (recommendationStatus.icon) {
+ append(this.container, $(`div${ThemeIcon.asCSSSelector(recommendationStatus.icon)}`));
+ }
+ append(this.container, $(`div.recommendation-text`, undefined, recommendationStatus.message));
+ }
+ this._onDidRender.fire();
+ }
+
+ private getRecommendationStatus(): { icon: ThemeIcon | undefined; message: string } | undefined {
+ if (!this.extension
+ || this.extension.deprecationInfo
+ || this.extension.state === ExtensionState.Installed
+ ) {
+ return undefined;
+ }
+ const extRecommendations = this.extensionRecommendationsService.getAllRecommendationsWithReason();
+ if (extRecommendations[this.extension.identifier.id.toLowerCase()]) {
+ const reasonText = extRecommendations[this.extension.identifier.id.toLowerCase()].reasonText;
+ if (reasonText) {
+ return { icon: starEmptyIcon, message: reasonText };
+ }
+ } else if (this.extensionIgnoredRecommendationsService.globalIgnoredRecommendations.indexOf(this.extension.identifier.id.toLowerCase()) !== -1) {
+ return { icon: undefined, message: localize('recommendationHasBeenIgnored', "You have chosen not to receive recommendations for this extension.") };
+ }
+ return undefined;
+ }
+}
+
// Rating icon
export const extensionRatingIconColor = registerColor('extensionIcon.starForeground', { light: '#DF6100', dark: '#FF8E00', hcDark: '#FF8E00', hcLight: textLinkForeground }, localize('extensionIconStarForeground', "The icon color for extension ratings."), true);
export const extensionVerifiedPublisherIconColor = registerColor('extensionIcon.verifiedForeground', { dark: textLinkForeground, light: textLinkForeground, hcDark: textLinkForeground, hcLight: textLinkForeground }, localize('extensionIconVerifiedForeground', "The icon color for extension verified publisher."), true);
diff --git a/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css b/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css
index 3c9a5a0e1b5..49d44c6e405 100644
--- a/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css
+++ b/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css
@@ -249,49 +249,36 @@
.extension-editor > .header > .details > .actions-status-container > .status {
line-height: 22px;
font-size: 90%;
- display: flex;
+ margin-top: 3px;
}
.extension-editor > .header > .details > .actions-status-container.list-layout > .status {
margin-top: 5px;
}
-.extension-editor > .header > .details > .actions-status-container > .status > .monaco-action-bar {
- height: 22px;
- margin-right: 2px;
-}
-
-.extension-editor > .header > .details > .actions-status-container > .status > .monaco-action-bar .extension-action {
- margin-top: 3px;
-}
-
-.extension-editor > .header > .details > .actions-status-container.list-layout > .status > .monaco-action-bar .extension-action {
- margin-top: 0px;
-}
-
-.extension-editor > .header > .details > .actions-status-container:not(.list-layout) > .status > .status-text {
- margin-top: 2px;
+.extension-editor > .header > .details > .actions-status-container > .status .codicon {
+ vertical-align: text-bottom;
}
.extension-editor > .header > .details > .pre-release-text p,
-.extension-editor > .header > .details > .actions-status-container > .status > .status-text p {
+.extension-editor > .header > .details > .actions-status-container > .status p {
margin-top: 0px;
margin-bottom: 0px;
}
.extension-editor > .header > .details > .pre-release-text a,
-.extension-editor > .header > .details > .actions-status-container > .status > .status-text a {
+.extension-editor > .header > .details > .actions-status-container > .status a {
color: var(--vscode-textLink-foreground)
}
.extension-editor > .header > .details > .pre-release-text a:hover,
-.extension-editor > .header > .details > .actions-status-container > .status > .status-text a:hover {
+.extension-editor > .header > .details > .actions-status-container > .status a:hover {
text-decoration: underline;
color: var(--vscode-textLink-activeForeground)
}
.extension-editor > .header > .details > .pre-release-text a:active,
-.extension-editor > .header > .details > .actions-status-container > .status > .status-text a:active {
+.extension-editor > .header > .details > .actions-status-container > .status a:active {
color: var(--vscode-textLink-activeForeground)
}
diff --git a/src/vs/workbench/contrib/extensions/common/extensions.ts b/src/vs/workbench/contrib/extensions/common/extensions.ts
index ec28a88e81f..eddd826fa33 100644
--- a/src/vs/workbench/contrib/extensions/common/extensions.ts
+++ b/src/vs/workbench/contrib/extensions/common/extensions.ts
@@ -9,7 +9,7 @@ import { IPager } from 'vs/base/common/paging';
import { IQueryOptions, ILocalExtension, IGalleryExtension, IExtensionIdentifier, InstallOptions, InstallVSIXOptions, IExtensionInfo, IExtensionQueryOptions, IDeprecationInfo } from 'vs/platform/extensionManagement/common/extensionManagement';
import { EnablementState, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { CancellationToken } from 'vs/base/common/cancellation';
-import { Disposable } from 'vs/base/common/lifecycle';
+import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IExtensionManifest, ExtensionType } from 'vs/platform/extensions/common/extensions';
import { URI } from 'vs/base/common/uri';
@@ -136,7 +136,7 @@ export interface IExtensionsConfiguration {
closeExtensionDetailsOnViewChange: boolean;
}
-export interface IExtensionContainer {
+export interface IExtensionContainer extends IDisposable {
extension: IExtension | null;
updateWhenCounterExtensionChanges?: boolean;
update(): void;
diff --git a/src/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts b/src/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts
index 062c0d23e29..41f221e0db0 100644
--- a/src/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts
+++ b/src/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts
@@ -65,10 +65,10 @@ export class ExplorerDecorationsProvider implements IDecorationsProvider {
return this._onDidChange.event;
}
- provideDecorations(resource: URI): IDecorationData | undefined {
+ async provideDecorations(resource: URI): Promise<IDecorationData | undefined> {
const fileStat = this.explorerService.findClosest(resource);
if (!fileStat) {
- return undefined;
+ throw new Error('ExplorerItem not found');
}
return provideDecorations(fileStat);
diff --git a/src/vs/workbench/contrib/localization/browser/localeService.ts b/src/vs/workbench/contrib/localization/browser/localeService.ts
index ea5f4383b6e..c59d84821b2 100644
--- a/src/vs/workbench/contrib/localization/browser/localeService.ts
+++ b/src/vs/workbench/contrib/localization/browser/localeService.ts
@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { language } from 'vs/base/common/platform';
-import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ILanguagePackItem } from 'vs/platform/languagePacks/common/languagePacks';
import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale';
@@ -32,5 +31,3 @@ export class WebLocaleService implements ILocaleService {
return true;
}
}
-
-registerSingleton(ILocaleService, WebLocaleService, true);
diff --git a/src/vs/workbench/contrib/localization/browser/localization.contribution.ts b/src/vs/workbench/contrib/localization/browser/localization.contribution.ts
index 79f2f0a777b..85716e8bcb9 100644
--- a/src/vs/workbench/contrib/localization/browser/localization.contribution.ts
+++ b/src/vs/workbench/contrib/localization/browser/localization.contribution.ts
@@ -4,7 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import { registerAction2 } from 'vs/platform/actions/common/actions';
+import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
+import { WebLocaleService } from 'vs/workbench/contrib/localization/browser/localeService';
import { ClearDisplayLanguageAction, ConfigureDisplayLanguageAction } from 'vs/workbench/contrib/localization/browser/localizationsActions';
+import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale';
+
+registerSingleton(ILocaleService, WebLocaleService, true);
// Register action to configure locale and related settings
registerAction2(ConfigureDisplayLanguageAction);
diff --git a/src/vs/workbench/contrib/localization/browser/localizationsActions.ts b/src/vs/workbench/contrib/localization/browser/localizationsActions.ts
index 5d51fb89d0f..5bdb7500724 100644
--- a/src/vs/workbench/contrib/localization/browser/localizationsActions.ts
+++ b/src/vs/workbench/contrib/localization/browser/localizationsActions.ts
@@ -45,7 +45,7 @@ export class ConfigureDisplayLanguageAction extends Action2 {
qp.placeholder = localize('chooseLocale', "Select Display Language");
if (installedLanguages?.length) {
- const items: Array<ILanguagePackItem | IQuickPickSeparator> = [{ type: 'separator', label: localize('installed', "Installed languages") }];
+ const items: Array<ILanguagePackItem | IQuickPickSeparator> = [{ type: 'separator', label: localize('installed', "Installed") }];
qp.items = items.concat(installedLanguages);
}
@@ -62,7 +62,7 @@ export class ConfigureDisplayLanguageAction extends Action2 {
if (newLanguages.length) {
qp.items = [
...qp.items,
- { type: 'separator', label: localize('available', "Available languages") },
+ { type: 'separator', label: localize('available', "Available") },
...newLanguages
];
}
diff --git a/src/vs/workbench/contrib/localization/electron-sandbox/localeService.ts b/src/vs/workbench/contrib/localization/electron-sandbox/localeService.ts
index 7f1a40e718c..86bc2246730 100644
--- a/src/vs/workbench/contrib/localization/electron-sandbox/localeService.ts
+++ b/src/vs/workbench/contrib/localization/electron-sandbox/localeService.ts
@@ -5,7 +5,6 @@
import { language } from 'vs/base/common/platform';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
-import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale';
@@ -14,6 +13,8 @@ import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/b
import { IExtensionsViewPaneContainer, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions';
import { ViewContainerLocation } from 'vs/workbench/common/views';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
+import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
+import { localize } from 'vs/nls';
export class NativeLocaleService implements ILocaleService {
_serviceBrand: undefined;
@@ -25,6 +26,7 @@ export class NativeLocaleService implements ILocaleService {
@ILanguagePackService private readonly languagePackService: ILanguagePackService,
@IPaneCompositePartService private readonly paneCompositePartService: IPaneCompositePartService,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
+ @IProgressService private readonly progressService: IProgressService
) { }
private async writeLocaleValue(locale: string | undefined): Promise<void> {
@@ -42,16 +44,26 @@ export class NativeLocaleService implements ILocaleService {
// Only Desktop has the concept of installing language packs so we only do this for Desktop
// and only if the language pack is not installed
if (!installedLanguages.some(installedLanguage => installedLanguage.id === languagePackItem.id)) {
- // Show the view so the user can see the language pack to be installed
- const viewlet = await this.paneCompositePartService.openPaneComposite(EXTENSIONS_VIEWLET_ID, ViewContainerLocation.Sidebar);
- (viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer).search(`@id:${languagePackItem.extensionId}`);
// Only actually install a language pack from Microsoft
if (languagePackItem.galleryExtension?.publisher.toLowerCase() !== 'ms-ceintl') {
+ // Show the view so the user can see the language pack that they should install
+ // as of now, there are no 3rd party language packs available on the Marketplace.
+ const viewlet = await this.paneCompositePartService.openPaneComposite(EXTENSIONS_VIEWLET_ID, ViewContainerLocation.Sidebar);
+ (viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer).search(`@id:${languagePackItem.extensionId}`);
return false;
}
- await this.extensionManagementService.installFromGallery(languagePackItem.galleryExtension);
+ await this.progressService.withProgress(
+ {
+ location: ProgressLocation.Notification,
+ title: localize('installing', "Installing {0} language support...", languagePackItem.label),
+ },
+ progress => this.extensionManagementService.installFromGallery(languagePackItem.galleryExtension!, {
+ // Setting this to false is how you get the extension to be synced with Settings Sync (if enabled).
+ isMachineScoped: false,
+ })
+ );
}
await this.writeLocaleValue(locale);
@@ -75,5 +87,3 @@ export class NativeLocaleService implements ILocaleService {
}
}
}
-
-registerSingleton(ILocaleService, NativeLocaleService, true);
diff --git a/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts b/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts
index b04105ab3c9..29726f689d2 100644
--- a/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts
+++ b/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts
@@ -25,6 +25,11 @@ import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/b
import { ViewContainerLocation } from 'vs/workbench/common/views';
import { registerAction2 } from 'vs/platform/actions/common/actions';
import { ClearDisplayLanguageAction, ConfigureDisplayLanguageAction } from 'vs/workbench/contrib/localization/browser/localizationsActions';
+import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
+import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale';
+import { NativeLocaleService } from 'vs/workbench/contrib/localization/electron-sandbox/localeService';
+
+registerSingleton(ILocaleService, NativeLocaleService, true);
// Register action to configure locale and related settings
registerAction2(ConfigureDisplayLanguageAction);
diff --git a/src/vs/workbench/contrib/mergeEditor/browser/editorGutter.ts b/src/vs/workbench/contrib/mergeEditor/browser/editorGutter.ts
index b850a842e5d..b01b1e9c46a 100644
--- a/src/vs/workbench/contrib/mergeEditor/browser/editorGutter.ts
+++ b/src/vs/workbench/contrib/mergeEditor/browser/editorGutter.ts
@@ -11,7 +11,7 @@ import { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model';
export class EditorGutter<
T extends IGutterItemInfo = IGutterItemInfo
- > extends Disposable {
+> extends Disposable {
private readonly scrollTop = observableFromEvent(
this._editor.onDidScrollChange,
(e) => this._editor.getScrollTop()
diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts b/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts
index 8fbc0999419..712c2369044 100644
--- a/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts
+++ b/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts
@@ -285,15 +285,15 @@ export class NotebookClipboardContribution extends Disposable {
}
if (PasteAction) {
- PasteAction.addImplementation(PRIORITY, 'notebook-clipboard', accessor => {
+ this._register(PasteAction.addImplementation(PRIORITY, 'notebook-clipboard', accessor => {
return this.runPasteAction(accessor);
- });
+ }));
}
if (CutAction) {
- CutAction.addImplementation(PRIORITY, 'notebook-clipboard', accessor => {
+ this._register(CutAction.addImplementation(PRIORITY, 'notebook-clipboard', accessor => {
return this.runCutAction(accessor);
- });
+ }));
}
}
diff --git a/src/vs/workbench/contrib/notebook/browser/extensionPoint.ts b/src/vs/workbench/contrib/notebook/browser/extensionPoint.ts
index b48922916a0..cdb8be3b643 100644
--- a/src/vs/workbench/contrib/notebook/browser/extensionPoint.ts
+++ b/src/vs/workbench/contrib/notebook/browser/extensionPoint.ts
@@ -131,21 +131,20 @@ const notebookRendererContribution: IJSONSchema = {
{
type: 'string',
},
- // todo@connor4312 + @mjbvz: uncomment this once it's ready for external adoption
- // {
- // type: 'object',
- // required: ['extends', 'path'],
- // properties: {
- // extends: {
- // type: 'string',
- // description: nls.localize('contributes.notebook.renderer.entrypoint.extends', 'Existing renderer that this one extends.'),
- // },
- // path: {
- // type: 'string',
- // description: nls.localize('contributes.notebook.renderer.entrypoint', 'File to load in the webview to render the extension.'),
- // },
- // }
- // }
+ {
+ type: 'object',
+ required: ['extends', 'path'],
+ properties: {
+ extends: {
+ type: 'string',
+ description: nls.localize('contributes.notebook.renderer.entrypoint.extends', 'Existing renderer that this one extends.'),
+ },
+ path: {
+ type: 'string',
+ description: nls.localize('contributes.notebook.renderer.entrypoint', 'File to load in the webview to render the extension.'),
+ },
+ }
+ }
]
},
[NotebookRendererContribution.hardDependencies]: {
diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts
index e678891f59a..9d87162b033 100644
--- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts
+++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts
@@ -75,7 +75,7 @@ export const RENDERER_EQUIVALENT_EXTENSIONS: ReadonlyMap<string, ReadonlySet<str
export const RENDERER_NOT_AVAILABLE = '_notAvailable';
-export type NotebookRendererEntrypoint = string | { extends: string; path: string };
+export type NotebookRendererEntrypoint = string | { readonly extends: string; readonly path: string };
export enum NotebookRunState {
Running = 1,
diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css
index 7b4684b2961..20f1af21202 100644
--- a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css
+++ b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css
@@ -109,15 +109,23 @@
/* padding must be on action-label because it has the bottom-border, because that's where the .checked class is */
}
+.settings-editor > .settings-header > .settings-header-controls .settings-tabs-widget > .monaco-action-bar .action-item.focused {
+ outline-offset: -1.5px;
+}
+
.settings-editor > .settings-header > .settings-header-controls .settings-tabs-widget > .monaco-action-bar .action-item .action-label {
text-transform: none;
font-size: 13px;
- padding-bottom: 7px;
+ padding-bottom: 6.5px;
padding-top: 7px;
padding-left: 8px;
padding-right: 8px;
}
+.settings-editor > .settings-header > .settings-header-controls .settings-tabs-widget > .monaco-action-bar .action-item .action-label .dropdown-icon {
+ padding-top: 2px;
+}
+
.settings-editor > .settings-header > .settings-header-controls .settings-tabs-widget > .monaco-action-bar .action-item .action-label:not(.checked):not(:focus) {
/* Add an extra pixel due to it not getting the outline */
padding-bottom: 8px;
diff --git a/src/vs/workbench/contrib/scm/browser/util.ts b/src/vs/workbench/contrib/scm/browser/util.ts
index 80d5d19302d..c8f4524d017 100644
--- a/src/vs/workbench/contrib/scm/browser/util.ts
+++ b/src/vs/workbench/contrib/scm/browser/util.ts
@@ -37,7 +37,7 @@ export function isSCMResource(element: any): element is ISCMResource {
return !!(element as ISCMResource).sourceUri && isSCMResourceGroup((element as ISCMResource).resourceGroup);
}
-const compareActions = (a: IAction, b: IAction) => a.id === b.id;
+const compareActions = (a: IAction, b: IAction) => a.id === b.id && a.enabled === b.enabled;
export function connectPrimaryMenu(menu: IMenu, callback: (primary: IAction[], secondary: IAction[]) => void, primaryGroup?: string): IDisposable {
let cachedDisposable: IDisposable = Disposable.None;
diff --git a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts
index 4a77f401057..41c02ea5f9b 100644
--- a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts
+++ b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts
@@ -1480,7 +1480,7 @@ namespace ConfiguringTask {
for (const required of typeDeclaration.required) {
const value = result.configures[required];
if (value) {
- label = label + ' ' + value;
+ label = label + ': ' + value;
break;
}
}
diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh
index 46fe4c4813b..b40e0e33562 100644
--- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh
+++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh
@@ -71,6 +71,14 @@ __vsc_command_complete() {
__vsc_update_cwd
}
+if [[ -o NOUNSET ]]; then
+ if [ -z "${RPROMPT-}" ]; then
+ RPROMPT=""
+ fi
+ if [ -z "${PREFIX-}" ]; then
+ PREFIX=""
+ fi
+fi
__vsc_update_prompt() {
__vsc_prior_prompt="$PS1"
__vsc_in_command_execution=""
diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts
index 34cdd7e2d3e..b8fd8ff6a1f 100644
--- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts
+++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts
@@ -929,10 +929,12 @@ export class TerminalService implements ITerminalService {
// Await the initialization of available profiles as long as this is not a pty terminal or a
// local terminal in a remote workspace as profile won't be used in those cases and these
// terminals need to be launched before remote connections are established.
- const isPtyTerminal = options?.config && 'customPtyImplementation' in options.config;
- const isLocalInRemoteTerminal = this._remoteAgentService.getConnection() && URI.isUri(options?.cwd) && options?.cwd.scheme === Schemas.vscodeFileResource;
- if (!isPtyTerminal && !isLocalInRemoteTerminal) {
- await this._terminalProfileService.profilesReady;
+ if (this._terminalProfileService.availableProfiles.length === 0) {
+ const isPtyTerminal = options?.config && 'customPtyImplementation' in options.config;
+ const isLocalInRemoteTerminal = this._remoteAgentService.getConnection() && URI.isUri(options?.cwd) && options?.cwd.scheme === Schemas.vscodeFileResource;
+ if (!isPtyTerminal && !isLocalInRemoteTerminal) {
+ await this._terminalProfileService.profilesReady;
+ }
}
const config = options?.config || this._terminalProfileService.availableProfiles?.find(p => p.profileName === this._terminalProfileService.getDefaultProfileName());
diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts
index 4caf924b497..cc3510f39dc 100644
--- a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts
+++ b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts
@@ -118,8 +118,11 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
}
public clearDecorations(): void {
- this._placeholderDecoration?.dispose();
- this._placeholderDecoration?.marker.dispose();
+ if (this._placeholderDecoration) {
+ this._placeholderDecoration.marker.dispose();
+ this._placeholderDecoration.dispose();
+ this._placeholderDecoration = undefined;
+ }
for (const value of this._decorations.values()) {
value.decoration.dispose();
dispose(value.disposables);
diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts
index 2aa2aa38445..42a7850a675 100644
--- a/src/vs/workbench/services/decorations/browser/decorationsService.ts
+++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts
@@ -398,7 +398,8 @@ export class DecorationsService implements IDecorationsService {
private _keepItem(map: DecorationEntry, provider: IDecorationsProvider, uri: URI, data: IDecorationData | undefined): IDecorationData | null {
const deco = data ? data : null;
- const old = map.set(provider, deco);
+ const old = map.get(provider);
+ map.set(provider, deco);
if (deco || old) {
// only fire event when something changed
this._onDidChangeDecorationsDelayed.fire(uri);
diff --git a/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts b/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts
index ea87ef0642a..7b25b8f9142 100644
--- a/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts
+++ b/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts
@@ -30,7 +30,7 @@ import { flatten } from 'vs/base/common/arrays';
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService';
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
-import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
+import { getRemoteName, parseAuthorityWithPort } from 'vs/platform/remote/common/remoteHosts';
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
import { IWebWorkerExtensionHostDataProvider, IWebWorkerExtensionHostInitData, WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
@@ -349,12 +349,12 @@ export abstract class ElectronExtensionService extends AbstractExtensionService
const authorityPlusIndex = remoteAuthority.indexOf('+');
if (authorityPlusIndex === -1) {
// This authority does not need to be resolved, simply parse the port number
- const lastColon = remoteAuthority.lastIndexOf(':');
+ const { host, port } = parseAuthorityWithPort(remoteAuthority);
return {
authority: {
authority: remoteAuthority,
- host: remoteAuthority.substring(0, lastColon),
- port: parseInt(remoteAuthority.substring(lastColon + 1), 10),
+ host,
+ port,
connectionToken: undefined
}
};
diff --git a/src/vs/workbench/workbench.sandbox.main.ts b/src/vs/workbench/workbench.sandbox.main.ts
index 99705ed5b01..dd9ddd715b1 100644
--- a/src/vs/workbench/workbench.sandbox.main.ts
+++ b/src/vs/workbench/workbench.sandbox.main.ts
@@ -83,7 +83,6 @@ import 'vs/workbench/services/files/electron-sandbox/elevatedFileService';
import 'vs/workbench/services/search/electron-sandbox/searchService';
import 'vs/workbench/services/workingCopy/electron-sandbox/workingCopyHistoryService';
import 'vs/workbench/services/userDataSync/browser/userDataSyncEnablementService';
-import 'vs/workbench/contrib/localization/electron-sandbox/localeService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IUserDataInitializationService, UserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit';
diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts
index 65562cad3ab..f0833043d64 100644
--- a/src/vs/workbench/workbench.web.main.ts
+++ b/src/vs/workbench/workbench.web.main.ts
@@ -62,7 +62,6 @@ import 'vs/workbench/services/files/browser/elevatedFileService';
import 'vs/workbench/services/workingCopy/browser/workingCopyHistoryService';
import 'vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService';
import 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
-import 'vs/workbench/contrib/localization/browser/localeService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
diff --git a/src/vscode-dts/vscode.proposed.documentPaste.d.ts b/src/vscode-dts/vscode.proposed.documentPaste.d.ts
index 1777c8d4145..29335e1df21 100644
--- a/src/vscode-dts/vscode.proposed.documentPaste.d.ts
+++ b/src/vscode-dts/vscode.proposed.documentPaste.d.ts
@@ -19,11 +19,11 @@ declare module 'vscode' {
* a {@link DataTransfer} and is passed back to the provider in {@link provideDocumentPasteEdits}.
*
* @param document Document where the copy took place.
- * @param range Range being copied in the `document`.
+ * @param ranges Ranges being copied in the `document`.
* @param dataTransfer The data transfer associated with the copy. You can store additional values on this for later use in {@link provideDocumentPasteEdits}.
* @param token A cancellation token.
*/
- prepareDocumentPaste?(document: TextDocument, range: Range, dataTransfer: DataTransfer, token: CancellationToken): void | Thenable<void>;
+ prepareDocumentPaste?(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, token: CancellationToken): void | Thenable<void>;
/**
* Invoked before the user pastes into a document.
@@ -31,16 +31,40 @@ declare module 'vscode' {
* In this method, extensions can return a workspace edit that replaces the standard pasting behavior.
*
* @param document Document being pasted into
- * @param range Currently selected range in the document.
+ * @param ranges Currently selected ranges in the document.
* @param dataTransfer The data transfer associated with the paste.
* @param token A cancellation token.
*
* @return Optional workspace edit that applies the paste. Return undefined to use standard pasting.
*/
- provideDocumentPasteEdits(document: TextDocument, range: Range, dataTransfer: DataTransfer, token: CancellationToken): ProviderResult<WorkspaceEdit | SnippetTextEdit>;
+ provideDocumentPasteEdits(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, token: CancellationToken): ProviderResult<DocumentPasteEdit>;
+ }
+
+ /**
+ * An operation applied on paste
+ */
+ interface DocumentPasteEdit {
+ /**
+ * The text or snippet to insert at the pasted locations.
+ */
+ readonly insertText: string | SnippetString;
+
+ /**
+ * An optional additional edit to apply on paste.
+ */
+ readonly additionalEdit?: WorkspaceEdit;
+ }
+
+ interface DocumentPasteProviderMetadata {
+ /**
+ * Mime types that `provideDocumentPasteEdits` should be invoked for.
+ *
+ * Use the special `files` mimetype to indicate the provider should be invoked if any files are present in the `DataTransfer`.
+ */
+ readonly pasteMimeTypes: readonly string[];
}
namespace languages {
- export function registerDocumentPasteEditProvider(selector: DocumentSelector, provider: DocumentPasteEditProvider): Disposable;
+ export function registerDocumentPasteEditProvider(selector: DocumentSelector, provider: DocumentPasteEditProvider, metadata: DocumentPasteProviderMetadata): Disposable;
}
}
diff --git a/src/vscode-dts/vscode.proposed.textEditorDrop.d.ts b/src/vscode-dts/vscode.proposed.textEditorDrop.d.ts
index 5468bc218cd..1b0d76db88d 100644
--- a/src/vscode-dts/vscode.proposed.textEditorDrop.d.ts
+++ b/src/vscode-dts/vscode.proposed.textEditorDrop.d.ts
@@ -7,12 +7,6 @@ declare module 'vscode' {
// https://github.com/microsoft/vscode/issues/142990
- export class SnippetTextEdit {
- snippet: SnippetString;
- range: Range;
- constructor(range: Range, snippet: SnippetString);
- }
-
/**
* Provider which handles dropping of resources into a text editor.
*
@@ -27,10 +21,25 @@ declare module 'vscode' {
* @param dataTransfer A {@link DataTransfer} object that holds data about what is being dragged and dropped.
* @param token A cancellation token.
*
- * @return A {@link SnippetTextEdit} or a thenable that resolves to such. The lack of a result can be
+ * @return A {@link DocumentDropEdit} or a thenable that resolves to such. The lack of a result can be
* signaled by returning `undefined` or `null`.
*/
- provideDocumentOnDropEdits(document: TextDocument, position: Position, dataTransfer: DataTransfer, token: CancellationToken): ProviderResult<SnippetTextEdit>;
+ provideDocumentOnDropEdits(document: TextDocument, position: Position, dataTransfer: DataTransfer, token: CancellationToken): ProviderResult<DocumentDropEdit>;
+ }
+
+ /**
+ * An edit operation applied on drop.
+ */
+ export interface DocumentDropEdit {
+ /**
+ * The text or snippet to insert at the drop location.
+ */
+ readonly insertText: string | SnippetString;
+
+ /**
+ * An optional additional edit to apply on drop.
+ */
+ readonly additionalEdit?: WorkspaceEdit;
}
export namespace languages {
diff --git a/yarn.lock b/yarn.lock
index 3e537569240..83a087110e6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -11390,10 +11390,10 @@ typescript@^2.6.2:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4"
integrity sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=
-typescript@^4.8.0-dev.20220518:
- version "4.8.0-dev.20220518"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.0-dev.20220518.tgz#3082c89c764daece904480552b9f2c3f5ce79c56"
- integrity sha512-yczRLiowXD4THxpe2DrClYXsmIRt9VPDft1dat4Le50mQwuUcmvdqD43o4hmlbNP7HpyeEYX51KXozGq1s7zlw==
+typescript@^4.8.0-dev.20220608:
+ version "4.8.0-dev.20220608"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.0-dev.20220608.tgz#6da2ea3c79307b1dfc1cb3692b142cc13f974a98"
+ integrity sha512-cayjhBae7omJ5MYxt4fO2PNW7kjYNCRqOOQbafxuzP0SWpqznzPROuNQqiBK1KJfgnRxBWeyqGBP52mdZDYZVw==
typical@^4.0.0:
version "4.0.0"