Merge branch 'main' into joh/voluminous-lobster

This commit is contained in:
Johannes 2022-06-09 09:08:20 +02:00
commit 3622010b64
No known key found for this signature in database
GPG key ID: 6DEF802A22264FCA
78 changed files with 971 additions and 485 deletions

View file

@ -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

7
.vscode/launch.json vendored
View file

@ -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",
],

View file

@ -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,

View file

@ -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,

View file

@ -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;

View file

@ -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'
}
});

View file

@ -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",

View file

@ -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.",

View file

@ -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'
}

View file

@ -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);
}

View file

@ -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);

View file

@ -0,0 +1 @@
#!/bin/sh

View file

@ -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);

View file

@ -0,0 +1,4 @@
#!/bin/sh
ELECTRON_RUN_AS_NODE="1" \
"$VSCODE_GIT_EDITOR_NODE" "$VSCODE_GIT_EDITOR_MAIN" $VSCODE_GIT_EDITOR_EXTRA_ARGS $@

View file

@ -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 {

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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 {

View file

@ -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",

View file

@ -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']
});
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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'),
]
});
});
});

View file

@ -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/**');

View file

@ -65,7 +65,7 @@
}
},
{
"scope": ["meta.embedded", "source.groovy.embedded"],
"scope": ["meta.embedded", "source.groovy.embedded", "meta.jsx.children"],
"settings": {
//"background": "#002451",
"foreground": "#FFFFFF"

View file

@ -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),

View file

@ -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);
});
});

View file

@ -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 () {

View file

@ -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');
});

View file

@ -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",

View file

@ -724,10 +724,21 @@ export interface CodeActionProvider {
/**
* @internal
*/
export interface DocumentPasteEditProvider {
prepareDocumentPaste?(model: model.ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<undefined | VSDataTransfer>;
export interface DocumentPasteEdit {
insertText: string | { snippet: string };
additionalEdit?: WorkspaceEdit;
}
provideDocumentPasteEdits(model: model.ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<WorkspaceEdit | SnippetTextEdit | undefined>;
/**
* @internal
*/
export interface DocumentPasteEditProvider {
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>;
}

View file

@ -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 handle = e.clipboardData?.getData(vscodeClipboardMime);
if (typeof handle !== 'string') {
return;
}
const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model);
if (!providers.length) {
return;
}
const handle = e.clipboardData?.getData(vscodeClipboardMime);
if (typeof handle !== 'string') {
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;
}

View file

@ -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 };
}
}

View file

@ -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();
}

5
src/vs/monaco.d.ts vendored
View file

@ -6758,11 +6758,6 @@ declare namespace monaco.languages {
eol?: editor.EndOfLineSequence;
};
export interface SnippetTextEdit {
range: IRange;
snippet: string;
}
/**
* Interface used to format a model
*/

View file

@ -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 {

View file

@ -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 };
}

View file

@ -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 });
});
});

View file

@ -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();
}

View file

@ -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,

View file

@ -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 {

View file

@ -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

View file

@ -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 {

View file

@ -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;

View file

@ -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: {

View file

@ -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);
}
}

View file

@ -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())));
}

View file

@ -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);
}
}
}
}));

View file

@ -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);
}

View file

@ -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);
});

View file

@ -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();

View file

@ -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}; }`);
}

View file

@ -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);

View file

@ -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)
}

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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
];
}

View file

@ -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);

View file

@ -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);

View file

@ -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()

View file

@ -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);
});
}));
}
}

View file

@ -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]: {

View file

@ -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,

View file

@ -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;

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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=""

View file

@ -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());

View file

@ -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);

View file

@ -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);

View file

@ -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
}
};

View file

@ -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';

View file

@ -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';

View file

@ -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;
}
}

View file

@ -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 {

View file

@ -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"